如果我有两个文件(单列),一个像这样(file1)
34
67
89
92
102
180
blue2
3454
第二个文件(file2)
23
56
67
69
102
200
如何找到两个文件(交集)中共有的元素?此示例中的预期输出为
67
102
请注意,每个文件中的项目(行)数不同。数字和字符串可以混合使用。它们可能不一定是排序的。每个项目只出现一次。
更新:
根据以下一些答案进行时间检查。
# generate some data
>shuf -n2000000 -i1-2352452 > file1
>shuf -n2000000 -i1-2352452 > file2
#@ilkkachu
>time (join <(sort "file1") <(sort "file2") > out1)
real 0m15.391s
user 0m14.896s
sys 0m0.205s
>head out1
1
10
100
1000
1000001
#@Hauke
>time (grep -Fxf "file1" "file2" > out2)
real 0m7.652s
user 0m7.131s
sys 0m0.316s
>head out2
1047867
872652
1370463
189072
1807745
#@Roman
>time (comm -12 <(sort "file1") <(sort "file2") > out3)
real 0m13.533s
user 0m13.140s
sys 0m0.195s
>head out3
1
10
100
1000
1000001
#@ilkkachu
>time (awk 'NR==FNR { lines[$0]=1; next } $0 in lines' "file1" "file2" > out4)
real 0m4.587s
user 0m4.262s
sys 0m0.195s
>head out4
1047867
872652
1370463
189072
1807745
#@Cyrus
>time (sort file1 file2 | uniq -d > out8)
real 0m16.106s
user 0m15.629s
sys 0m0.225s
>head out8
1
10
100
1000
1000001
#@Sundeep
>time (awk 'BEGIN{while( (getline k < "file1")>0 ){a[k]}} $0 in a' file2 > out5)
real 0m4.213s
user 0m3.936s
sys 0m0.179s
>head out5
1047867
872652
1370463
189072
1807745
#@Sundeep
>time (perl -ne 'BEGIN{ $h{$_}=1 while <STDIN> } print if $h{$_}' <file1 file2 > out6)
real 0m3.467s
user 0m3.180s
sys 0m0.175s
>head out6
1047867
872652
1370463
189072
1807745
perl 版本最快,awk 紧随其后。所有输出文件都具有相同的行数。
为了比较,我对输出进行了数字排序,以便输出相同。
#@ilkkachu
>time (join <(sort "file1") <(sort "file2") | sort -k1n > out1)
real 0m17.953s
user 0m5.306s
sys 0m0.138s
#@Hauke
>time (grep -Fxf "file1" "file2" | sort -k1n > out2)
real 0m12.477s
user 0m11.725s
sys 0m0.419s
#@Roman
>time (comm -12 <(sort "file1") <(sort "file2") | sort -k1n > out3)
real 0m16.273s
user 0m3.572s
sys 0m0.102s
#@ilkkachu
>time (awk 'NR==FNR { lines[$0]=1; next } $0 in lines' "file1" "file2" | sort -k1n > out4)
real 0m8.732s
user 0m8.320s
sys 0m0.261s
#@Cyrus
>time (sort file1 file2 | uniq -d > out8)
real 0m19.382s
user 0m18.726s
sys 0m0.295s
#@Sundeep
>time (awk 'BEGIN{while( (getline k < "file1")>0 ){a[k]}} $0 in a' file2 | sort -k1n > out5)
real 0m8.758s
user 0m8.315s
sys 0m0.255s
#@Sundeep
>time (perl -ne 'BEGIN{ $h{$_}=1 while <STDIN> } print if $h{$_}' <file1 file2 | sort -k1n > out6)
real 0m7.732s
user 0m7.300s
sys 0m0.310s
>head out1
1
2
3
4
5
现在所有输出都相同。
简单
comm
+sort
解决方案:-12
- 抑制列1
和2
(分别对FILE1
和唯一的FILE2
行),因此只输出公共行(出现在两个文件中)在
awk
中,这会将第一个文件完全加载到内存中:或者,如果您想跟踪给定行出现的次数:
join
可以这样做,尽管它确实需要对输入文件进行排序,所以你需要先这样做,这样做会丢失原始顺序:awk
这是一个很好的解决方案,因为(对于大文件)它应该是最快的,因为它省略了多次打印相同的条目并在匹配后再次检查条目。
grep
如果它在 中多次出现,这将多次输出相同的条目
file2
。种类
为了好玩(应该比 慢得多
grep
):使用 GNU uniq:
输出:
略有不同的
awk
版本和等效perl
版本连续三个运行报告的时间