在一个文件中打印行匹配另一个文件中的模式

Jon*_*Jon 15 unix awk grep sed extract

我有一个超过40.000行(file1)的文件,我想提取与file2中的模式匹配的行(约6000行).我像这样使用grep,但它很慢: grep -f file2 file1 > out

有没有更快的方法来使用awksed

这是我文件的一些摘录:

File1:
scitn003869.2| scign003869 CGCATGTGTGCATGTATTATCGTATCCCTTG
scitn007747.1| scign007747  CACGCAGACGCAGTGGAGCATTCCAGGTCACAA
scitn003155.1| scign003155  TAAAAATCGTTAGCACTCGCTTGGTACACTAAC
scitn018252.1| scign018252  CGTGTGTGTGCATATGTGTGCATGCGTG
scitn004671.2| scign004671  TCCTCAGGTTTTGAAAGGCAGGGTAAGTGCT
Run Code Online (Sandbox Code Playgroud)

File2:
scign000003
scign000004
scign000005
scign004671
scign000013
Run Code Online (Sandbox Code Playgroud)

`

gle*_*man 27

尝试 grep -Fwf file2 file1 > out

-F选项指定纯字符串匹配,因此应该更快,而不必使用正则表达式引擎.

  • 我的grep man页面说:"fgrep与grep -F相同.直接调用egrep或fgrep不推荐使用,......" (4认同)

Ed *_*ton 14

以下是如何在awk中执行此操作:

awk 'NR==FNR{pats[$0]; next} $2 in pats' File2 File1
Run Code Online (Sandbox Code Playgroud)

使用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
Run Code Online (Sandbox Code Playgroud)

即它和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
Run Code Online (Sandbox Code Playgroud)

这是我得到的perl脚本Mark的发布时间:

$ time ./go.pl > out2

real    0m0.203s
user    0m0.124s
sys     0m0.062s
Run Code Online (Sandbox Code Playgroud)

  • 虽然这可能会做OP意味着和想要的事情,并且我确实看到你暗示它并将其描述为避免错误匹配的好处,OP应该意识到它实际上并不像他的代码那样做.他的代码会在线上的任何地方找到匹配项,而你的代码只会在第二个字段中找到匹配项. (2认同)

Mar*_*ell 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
Run Code Online (Sandbox Code Playgroud)

FNR==NR部分指定只有在处理第一个输入文件(file2)时才应用花括号后面的内容.它说要保存你在阵列中寻找的所有单词a[].第二组花括号中的位适用于第二个文件的处理...当读入每一行时,将其与所有元素进行比较a[],如果找到任何元素,则打印该行.这就是所有人!

  • 使用`if(index($ 0,a [j]){print; break }`可以获得一些效率 (3认同)

Mar*_*ell 5

只是为了好玩,这里有一个 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};
}
Run Code Online (Sandbox Code Playgroud)

以下是根据 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
Run Code Online (Sandbox Code Playgroud)