如何跨多个文件提取公共行?

时间:2016-05-09 23:33:03

标签: perl shell grep comm

我有15个不同的文件,我想要一个新文件,其中只包含所有文件中的公共行。例如:

File1:

id1
id2
id3

file2:

id2
id3
id4

file3:
id10
id2
id3

file4

id100
id45
id3
id2

I need the output be like:

newfile:

id2 
id3

我知道这个命令适用于每对文件:

grep -w -f file1 file2>输出

但是我需要一个命令来处理2个以上的文件。

有什么建议吗?

3 个答案:

答案 0 :(得分:6)

Perl救援:

perl -lne 'BEGIN { $count = @ARGV }
           $h{$_}{$ARGV} = 1;
           }{
           print $_ for grep $count == keys %{ $h{$_} }, keys %h
           ' file* > newfile
  • -n逐行读取输入文件
  • -lprint
  • 添加换行符
  • @ARGV数组包含输入文件名,将$count分配给BEGIN,只计算它们
  • $ARGV包含当前输入文件的名称
  • $_包含从文件中读取的当前行。
  • %h哈希包含id作为键,每个键包含一个哈希引用,文件名包含id作为键
  • }{是"爱斯基摩人的问候"运算符,它引入了输入耗尽后运行的代码
  • 我们只输出其文件数等于所有文件数的ID。它适用于任意数量的文件。

答案 1 :(得分:3)

使用grep

同一个技巧可以多次使用:

$ grep -w -f file1 file2 | grep -w -f file3 | grep -w -f file4
id2
id3

顺便说一句,如果您正在寻找完全匹配,而不是正则表达式匹配,那么使用-F标志会更好更快:

$ grep -wFf file1 file2 | grep -wFf file3 | grep -wFf file4
id2
id3

使用awk

$ awk 'FNR==1{nfiles++; delete fseen} !($0 in fseen){fseen[$0]++; seen[$0]++} END{for (key in seen) if (seen[key]==nfiles) print key}' file1 file2 file3 file4
id3
id2
  • FNR==1{nfiles++; delete fseen}

    每当我们开始阅读新文件时,我们会做两件事:(1)递增文件计数器nfiles。 (2)删除数组fseen

  • !($0 in fseen){fseen[$0]; seen[$0]++}

    如果当前行不是fseen中的键,则将其添加到fseen并在seen中增加此行的计数。

  • END{for (key in seen) if (seen[key]==nfiles) print key}

    在我们读完最后一个文件的最后一行后,我们会查看seen中的每个键。如果该密钥的计数等于我们已读取的文件数nfiles,那么我们将打印该密钥。

答案 2 :(得分:1)

     grep -hxf file1 file2 file3 file4 |sort -u
     id2
     id3

     # For storing it to any file, 
     grep -hxf file1 file2 file3 file4 |sort -u > output.txt