【问题标题】:compare 2 files, find a string, and report several lines from one of them比较 2 个文件,找到一个字符串,并从其中一个文件中报告几行
【发布时间】:2014-01-11 19:18:10
【问题描述】:

我想比较并报告 2 个文件中的相似字符串: 每次读取file1的1行,在file2中搜索字符串,如果可以在file2中找到,则打印前一行,字符串和字符串后的2行

infile2:

john
jack
jeff

infile1:

22894
john
street3
city
56438
danny
street2
city
22894
john
street3
city
33456
jeff
street2
city
22894
john
street3
city

输出

22894
john
street3
city
22894
john
street3
city
33456
jeff
street2
city
22894
john
street3
city

我可以为此编写一个 perl 脚本 perl script.pl infile2 infile1

#!/usr/bin/perl
use warnings;
use strict;


my ($infile1) = $ARGV[0];
my ($infile2) = $ARGV[1];
open(my $fh1, "<$infile1");
open(my $fh2, "<$infile2");

while(( my @lines = map ~~<$fh1>, 1 .. 4 )[0] and (my $names = <$fh2>)) {
    #print $lines[1];
    #print "\n";        


        if ($lines[1] eq $names){
                print ("$lines[0]$lines[1]$lines[2]$lines[3]");}
                }
print ("\n");

但我只得到

22894
john
street3
city

【问题讨论】:

  • 缺少一些东西:样本输入、样本输出和[更重要的]您的尝试。
  • 这绝对是太宽泛了。
  • 对我来说听起来像grep。 grep -f file1 -B1 -A2 file2 或许?
  • @TLP 我认为您的评论是一个完美的解决方案 - 您可以发布作为答案。我会在 grep 中添加 -w,以确保它匹配整个单词。
  • @fedorqui 好吧,我不确定这是否是他想要的,或者是否有效。但也许值得以评论的形式提示。

标签: perl awk


【解决方案1】:

这是我认为您至少真正需要的,以避免在您的地址记录文件的其他部分出现错误匹配:

$ awk '
NR==FNR {names[$0]; next }
{
    lineNr = ((FNR+3)%4)+1
    rec = rec $0 ORS
}
lineNr == 2 { name = $0 }
lineNr == 4 {
    if (name in names) {
        printf "%s", rec
    }
    rec=""
}
' file2 file1
22894
john
street3
city
22894
john
street3
city
33456
jeff
street2
city
22894
john
street3
city

【讨论】:

    【解决方案2】:

    这是另一个选择:

    use strict;
    use warnings;
    
    my ( $file2, $last ) = pop;
    my %hash = map { chomp; $_ => 1 } <>;
    
    push @ARGV, $file2;
    while (<>) {
        chomp;
        print "$last\n$_\n" . <> . <> if $hash{$_};
        $last = $_;
    }
    

    用法:perl script.pl inFile2 inFile1 [&gt;outFile]

    最后一个可选参数将输出定向到文件。

    inFiles 以您的用法命名;较小的专有名称文件排在第一位。

    第一个pops 关闭并保存第二个文件名以供以后使用,然后创建专有名称的哈希。然后它遍历第二个文件,如果当前行在正确名称的文件中,则打印最后两行和下两行。变量$last 不会立即初始化,因为直到有前一行才会发生匹配。

    希望这会有所帮助!

    【讨论】:

      【解决方案3】:

      您的输入文件

       root@Aix:/tmp# cat file2
       john
       jack
       jeff
      
       root@Aix:/tmp# cat file1
       22894
       john
       street3
       city
       56438
       danny
       street2
       city
       22894
       john
       street3
       city
       33456
       jeff
       street2
       city
       22894
       john
       street3
       city
      

      Awk 代码

       root@Aix:/tmp# cat test.sh
      
       awk '     FNR==NR{
                         A[$1]             # Array 'A' holds key to search 
                         next
                        }
       # if previous and column1 of file1 in found in Array 'A' of file2 
       (p && ($1 in A)){
      
                         # counter reset after search found
                         i=0 
      
                         # We found that key we found, so print previous line and current line            
                         print p RS $0     
      
                         # Number of lines to print after key found
                         while(++i<=number_of_lines)
                                      {     
                                       getline
                                       print
                                      }
                      }
      
                      {
                        # Previous line is assigned to variable p
                        p=$0
                      }
          ' number_of_lines="2" file2 file1
      

      结果

       # sh test.sh
       22894
       john
       street3
       city
       22894
       john
       street3
       city
       33456
       jeff
       street2
       city
       22894
       john
       street3
       city
      

      如果您想在 Solaris/SunOS system 上尝试此操作,请将 awk 更改为 /usr/xpg4/bin/awk 、 /usr/xpg6/bin/awk 或 nawk

      根据需要更改number_of_lines="2"。

      【讨论】:

        【解决方案4】:

        这是一个 awk 解决方案:

        awk -f a.awk file2 file1
        

        a.awk 在哪里:

        NR==FNR {
            a[$1]++
            next
        }
        {
            b[FNR]=$0
        }
        
        END {
            for (i=1; i<=FNR; i++)
                if (b[i] in a) 
                    for (j=i-1; j<=i+2; j++)
                        print b[j]
        }
        

        输出:

        22894
        john
        street3
        city
        22894
        john
        street3
        city
        33456
        jeff
        street2
        city
        22894
        john
        street3
        city
        

        【讨论】:

        • 将第一个 END 循环更改为 for (i=2; i&lt;FNR; i+=4) 以仅匹配名称字段,我认为这是真正需要的,否则如果有人住在名为 john 的城镇,您将获得部分打印前面和后面的记录。
        • @EdMorton 是的..这可能是需要的..但​​我更喜欢懒惰..也给 OP 留下一些惊喜:)
        • 知道了。这有点像拆开圣诞礼物,但每次在新输入上运行脚本时你都可以这样做:-)。
        猜你喜欢
        • 2022-01-11
        • 1970-01-01
        • 1970-01-01
        • 2018-12-18
        • 2020-05-18
        • 2020-01-11
        • 2019-08-07
        • 2023-03-18
        • 2023-01-16
        相关资源
        最近更新 更多