我有一个超过40.000行(file1)的文件,我想提取与file2中的模式匹配的行(大约6000行)。我像这样使用grep,但它很慢:
grep -f file2 file1 > out
使用awk
或sed
?
以下是我文件中的一些摘录:
File1:
scitn003869.2| scign003869 CGCATGTGTGCATGTATTATCGTATCCCTTG
scitn007747.1| scign007747 CACGCAGACGCAGTGGAGCATTCCAGGTCACAA
scitn003155.1| scign003155 TAAAAATCGTTAGCACTCGCTTGGTACACTAAC
scitn018252.1| scign018252 CGTGTGTGTGCATATGTGTGCATGCGTG
scitn004671.2| scign004671 TCCTCAGGTTTTGAAAGGCAGGGTAAGTGCT
File2:
scign000003
scign000004
scign000005
scign004671
scign000013
`
答案 0 :(得分:25)
尝试grep -Fwf file2 file1 > out
-F
选项指定纯字符串匹配,所以应该更快,而不必使用正则表达式引擎。
答案 1 :(得分:14)
以下是如何在awk中执行此操作:
awk 'NR==FNR{pats[$0]; next} $2 in pats' File2 File1
使用60,000行File1(您的File1重复8000次)和6,000 File2(您的重复1200次):
$ time grep -Fwf File2 File1 > ou2
real 0m0.094s
user 0m0.031s
sys 0m0.062s
$ time awk 'NR==FNR{pats[$0]; next} $2 in pats' File2 File1 > ou1
real 0m0.094s
user 0m0.015s
sys 0m0.077s
$ diff ou1 ou2
即。它和grep一样快。需要注意的一点是,awk解决方案允许您选择要匹配的特定字段,因此如果File2中的任何内容显示在File1中的任何其他位置,您将不会得到错误匹配。它还允许您一次匹配整个字段,因此如果您的目标字符串是各种长度,并且您不希望“scign000003”匹配“scign0000031”(尽管grep的-w为此提供了类似的保护)。
为了完整起见,这是其他awk解决方案发布的时间:elsethread:
$ time awk 'BEGIN{i=0}FNR==NR{a[i++]=$1;next}{for(j=0;j<i;j++)if(index($0,a[j]))print $0}' File2 File1 > ou3
real 3m34.110s
user 3m30.850s
sys 0m1.263s
这是我为Perl脚本Mark发布的时间:
$ time ./go.pl > out2
real 0m0.203s
user 0m0.124s
sys 0m0.062s
答案 2 :(得分:6)
你可以试试这个awk:
awk 'BEGIN{i=0}
FNR==NR { a[i++]=$1; next }
{ for(j=0;j<i;j++)
if(index($0,a[j]))
{print $0;break}
}' file2 file1
FNR==NR
部分指定仅在处理第一个输入文件(file2
)时应用花括号后面的内容。它表示要在数组a[]
中保存您要查找的所有单词。第二组花括号中的位适用于第二个文件的处理...当读入每一行时,将其与a[]
的所有元素进行比较,如果找到任何元素,则打印该行。这就是所有人!
答案 3 :(得分:3)
只是为了好玩,这是一个Perl版本:
#!/usr/bin/perl
use strict;
use warnings;
my %patterns;
my $srch;
# Open file and get patterns to search for
open(my $fh2,"<","file2")|| die "ERROR: Could not open file2";
while (<$fh2>)
{
chop;
$patterns{$_}=1;
}
# Now read data file
open(my $fh1,"<","file1")|| die "ERROR: Could not open file1";
while (<$fh1>)
{
(undef,$srch,undef)=split;
print $_ if defined $patterns{$srch};
}
以下是一些时间,每个Ed的文件创建方法使用60,000行file1和6,000行file2:
time awk 'NR==FNR{pats[$0]; next} $2 in pats' file2 file1 > out
real 0m0.202s
user 0m0.197s
sys 0m0.005s
time ./go.pl > out2
real 0m0.083s
user 0m0.079s
sys 0m0.004s
答案 4 :(得分:3)
只是为了学习:我解决了同样的问题,我提出了各种解决方案(包括read $line
循环等)。当我到达上面找到的grep
单行时,我仍然得到了错误的输出。然后我意识到我的PATTERN文件有2个尾随行......所以grep
从我的数据库中获取了所有的行。道德:检查尾随空格/行。此外,在具有数百个模式的更大数据集上运行命令,time
甚至无法计数。