使用-w(--word-regexp)标志为什么grep如此缓慢和内存密集?

时间:2016-10-06 10:38:12

标签: bash shell unix awk grep

我在文件和数据文件(大小约为3.2Gb)中有一个id列表,我想提取数据文件中包含id和下一行的行。我做了以下事情:

grep -A1 -Ff file.ids file.data | grep -v "^-" > output.data

这很有用,但也提取了不需要的子字符串,例如,如果id为EA4,它也会用EA40拉出这些行。

所以我尝试使用相同的命令,但将-w--word-regexp)标记添加到第一个grep以匹配整个单词。但是,我发现我的命令现在运行了> 1小时(而不是~26秒),并且还开始使用10千兆字节的内存,所以我不得不杀死这份工作。

为什么添加-w会使命令变得如此缓慢并且内存占用?如何有效地运行此命令以获得所需的输出?谢谢

file.ids看起来像这样:

>EA4
>EA9

file.data看起来像这样:

>EA4 text
data
>E40 blah
more_data
>EA9 text_again
data_here

output.data看起来像这样:

>EA4 text
data
>EA9 text_again
data_here

1 个答案:

答案 0 :(得分:8)

grep -F string file只是在文件中查找string的出现次数,但grep -w -F string file必须检查string之前和之后的每个字符,以查看它们是否为单词字符或不。那些额外工作的很多和一个可能的实现方法是首先将行分成每个可能的非单词字符分隔的字符串,当然重叠,这样可能会占用很多记忆,但如果这是导致你的记忆使用的原因,那就是idk。

在任何情况下,grep只是这个工作的错误工具,因为你只想匹配输入文件中的特定字段,你应该使用awk代替:

$ awk 'NR==FNR{ids[$0];next} /^>/{f=($1 in ids)} f' file.ids file.data
>EA4 text
data
>EA9 text_again
data_here

以上假设您的数据"行无法以>开头。如果他们可以告诉我们如何识别数据线与id线。

请注意,无论data行之间有多少id行,即使有0或100行,上述内容也会有效:

$ cat file.data
>EA4 text
>E40 blah
more_data
>EA9 text_again
data 1
data 2
data 3

$ awk 'NR==FNR{ids[$0];next} /^>/{f=($1 in ids)} f' file.ids file.data
>EA4 text
>EA9 text_again
data 1
data 2
data 3

另外,您不需要将输出传递给grep -v

grep -A1 -Ff file.ids file.data | grep -v "^-" > output.data

只需在一个脚本中完成所有操作:

awk 'NR==FNR{ids[$0];next} /^>/{f=($1 in ids)} f && !/^-/' file.ids file.data