3

我有 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 文件 1 文件 2 > 输出

但我需要一个命令来处理超过 2 个文件。

请问有什么建议吗?

4

4 回答 4

6

Perl 的救援:

perl -lne 'BEGIN { $count = @ARGV }
           $h{$_}{$ARGV} = 1;
           }{
           print $_ for grep $count == keys %{ $h{$_} }, keys %h
           ' file* > newfile
  • -n逐行读取输入文件
  • -l添加换行符print
  • @ARGV数组包含输入文件名,将其分配给$countningBEGIN只是计算它们
  • $ARGV包含当前输入文件的名称
  • $_包含从文件中读取的当前行。
  • 散列包含 id 作为键,每个键都包含一个散列引用,其中%h包含包含 id 作为键的文件名
  • }{是“Eskimo greeting”操作符,它引入了在输入用完后运行的代码
  • 我们只输出文件数等于所有文件数的id。它适用于任意数量的文件。
于 2016-05-09T23:39:23.547 回答
4

使用 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]++}

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

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

    在我们读完最后一个文件的最后一行之后,我们查看seen. 如果该键的计数等于我们已读取的文件数nfiles,则我们打印该键。

于 2016-05-09T23:37:16.547 回答
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
于 2016-05-10T06:34:08.543 回答
0

zet命令提供输入文件之间的集合操作。使用该intersect选项获取所有输入文件的公共行。输入内容不必排序。输出顺序将与输入行的顺序相同。

$ zet intersect file1 file2 file3 file4
id2
id3

以下是注释部分的一些相关细节:

  • 每个输出行只出现一次,因为我们将文件视为集合,将行视为它们的元素。
  • Zet 将整个文件读入内存。它的内存使用量大致与其最大参数的文件大小加上(最终)输出的大小成正比。
于 2021-09-25T10:00:38.047 回答