如何跨多个文件提取公共行?
how to extract common lines across multiple file?
我有 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 个以上的文件。
有什么建议吗?
使用 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} !([=12=] in fseen){fseen[[=12=]]++; seen[[=12=]]++} 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
.
!([=17=] in fseen){fseen[[=17=]]; seen[[=17=]]++}
如果当前行不是 fseen
中的键,则将其添加到 fseen
并增加此行在 seen
中的计数。
END{for (key in seen) if (seen[key]==nfiles) print key}
读完最后一个文件的最后一行后,我们查看 seen
中的每个键。如果该键的计数等于我们已读取的文件数,nfiles
,那么我们打印该键。
Perl 来拯救:
perl -lne 'BEGIN { $count = @ARGV }
$h{$_}{$ARGV} = 1;
}{
print $_ for grep $count == keys %{ $h{$_} }, keys %h
' file* > newfile
-n
逐行读取输入文件
-l
向 print
添加换行符
-
@ARGV
数组包含输入文件名,在 BEGIN
将其分配给 $count
只是计算它们
$ARGV
包含当前输入文件的名称
$_
包含从文件中读取的当前行。
%h
散列包含 id 作为键,每个键包含一个散列引用,文件名包含 id 作为键
}{
是 "Eskimo greeting" 运算符,它引入了一旦输入耗尽就运行的代码
- 我们只输出文件数等于所有文件数的id。它适用于任意数量的文件。
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
zet 命令提供输入文件之间的集合操作。使用 intersect
选项获取所有输入文件的公共行。输入内容不必排序。输出顺序将与输入行的顺序相同。
$ zet intersect file1 file2 file3 file4
id2
id3
这里有一些相关的细节from the notes section:
- 每个输出行只出现一次,因为我们将文件视为集合,将行视为它们的元素。
- Zet 将整个文件读入内存。它的内存使用量大致与其最大参数的文件大小加上(最终)输出的大小成正比。
我有 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 个以上的文件。
有什么建议吗?
使用 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} !([=12=] in fseen){fseen[[=12=]]++; seen[[=12=]]++} 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
.!([=17=] in fseen){fseen[[=17=]]; seen[[=17=]]++}
如果当前行不是
fseen
中的键,则将其添加到fseen
并增加此行在seen
中的计数。END{for (key in seen) if (seen[key]==nfiles) print key}
读完最后一个文件的最后一行后,我们查看
seen
中的每个键。如果该键的计数等于我们已读取的文件数,nfiles
,那么我们打印该键。
Perl 来拯救:
perl -lne 'BEGIN { $count = @ARGV }
$h{$_}{$ARGV} = 1;
}{
print $_ for grep $count == keys %{ $h{$_} }, keys %h
' file* > newfile
-n
逐行读取输入文件-l
向print
添加换行符
-
@ARGV
数组包含输入文件名,在BEGIN
将其分配给$count
只是计算它们 $ARGV
包含当前输入文件的名称$_
包含从文件中读取的当前行。%h
散列包含 id 作为键,每个键包含一个散列引用,文件名包含 id 作为键}{
是 "Eskimo greeting" 运算符,它引入了一旦输入耗尽就运行的代码- 我们只输出文件数等于所有文件数的id。它适用于任意数量的文件。
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
zet 命令提供输入文件之间的集合操作。使用 intersect
选项获取所有输入文件的公共行。输入内容不必排序。输出顺序将与输入行的顺序相同。
$ zet intersect file1 file2 file3 file4
id2
id3
这里有一些相关的细节from the notes section:
- 每个输出行只出现一次,因为我们将文件视为集合,将行视为它们的元素。
- Zet 将整个文件读入内存。它的内存使用量大致与其最大参数的文件大小加上(最终)输出的大小成正比。