假设我有两个文件,文件 A:
a,abcdef
b,bcdefa
c,cdefab
a,defabc
b,efabcd
c,fabcde
文件 B:
a
b
我正在寻找的输出是:
a,abcdef
b,bcdefa
a,defabc
b,efabcd
因此,基本上,我想使用标准 unix 命令从文件 A 中选择第一列与文件 B 中的任意值匹配的行。一种awk {if (file_b contains $1} print $1,$2
,但效率更高。
文件 A 中的预期行数超过 2000 万,文件 B 中的预期行数超过 100 万。必须运行时间为 O(n),因此包含步骤可能应该依赖于哈希表。
答案1
有许多实现此目的的方法。这里有几个,但使用 Perl 的方法速度要快几个数量级。为了完整起见,我把其他方法也包括进来了:
Perl 和哈希,速度快得离谱
perl -e 'open(A,"fileB"); while(<A>){chomp; $k{$_}++} while(<>){@a=split(/,/); print if defined $k{$a[0]}}' fileA
gawk 和关联数组,速度慢得多
gawk '{if(FILENAME==ARGV[1]){array[$1]=1} else{if($1 in array){print}}}' fileA fileB
grep
,慢得离谱。你需要稍微修改一下文件 B,让模式只在第一行匹配sed 's/\(.\)/^\1/' fileB > fileC grep -f fileC fileA
我创建了几个测试文件,结果发现 Perl 解决方案是很多比以下更快grep
:
$ head -2 fileA
GO:0032513_GO:0050129
GO:0050129_GO:0051712
$ head -2 fileB
GO:0032513_GO:0050129
GO:0050129_GO:0051712
$ wc -l fileA fileB
1500000 fileA
20000000 fileB
$ time perl -e 'open(A,"fileB"); while(<A>){chomp; $k{$_}++}
while(<>){@a=split(/,/); print if defined $k{$a[0]}}' fileA > /dev/null
real 0m41.354s
user 0m37.370s
sys 0m3.960s
$ time gawk '{if(FILENAME==ARGV[1]){array[$1]=1}
else{if($1 in array){print}}}' fileA fileB
real 2m30.963s
user 1m23.857s
sys 0m9.385s
$ time (join -t, <(sort -n fileA) <(sort -n fileB) >/dev/null)
real 8m29.532s
user 13m52.576s
sys 1m22.029s
因此,Perl 脚本可以遍历 2000 万行文件,查找 150 万个模式,并在约 40 秒内完成。还不错。其他两个脚本要慢得多,gawk
需要 2.5 分钟,而其中grep
一个脚本已经运行了 15 分钟以上。Perl 毫无疑问胜出。
答案2
这应该可以解决问题:
join -t, <(sort A) <(sort B)
答案3
我还是不明白你想做什么....你已经在 awk stmt 中做了一些事情。
grep 是基本的,基于一种基于可能匹配索引的非常高效和快速的算法.... awk 进行单独的比较和检查,所以这应该很快.... wrt awk,这里
for pat in `cat zfile2` ; do grep -i "$pat," zfile1 ; done;
这很好用......
$ for pat in `cat zfile2` ; do grep -i "$pat," zfile1 ; done;
a,abcdef
a,defabc
b,bcdefa
b,efabcd
这有帮助吗?