grep如何运行如此之快?

时间:2012-09-27 20:45:40

标签: unix grep

我对shell中GREP的功能感到非常惊讶,早些时候我曾经在java中使用substring方法但现在我使用GREP并且它在几秒钟内执行,它比我使用的java代码快得多写作。(根据我的经验,我可能错了)

话虽如此,我还是无法弄清楚它是如何发生的?网上也没有太多可用。

任何人都可以帮我吗?

2 个答案:

答案 0 :(得分:149)

假设您的问题专门针对GNU grep。以下是作者Mike Haertel的说明:

  

GNU grep很快,因为它在每个输入字节中都能看到它。

     

GNU grep很快,因为它为每个执行非常少的指令   BYTE那个    看看。

     

GNU grep使用着名的Boyer-Moore算法,该算法首先出现   对于目标字符串的最后一个字母,并使用查找表   告诉它只要找到一个,它可以在输入中跳过多远   不匹配的角色。

     

GNU grep还展开了Boyer-Moore的内循环,并设置了   Boyer-Moore delta表条目以这种方式不需要   在每个展开的步骤中执行循环退出测试。结果是   在极限情况下,GNU grep平均少于3 x86指令   为它实际看到的每个输入字节执行(并且它跳过许多   字节完全)。

     

GNU grep使用原始Unix输入系统调用并避免复制数据   看完之后此外,GNU grep AVOIDS打破了输入   行。寻找新行会使grep减慢一倍   好几次,因为找到它必须要看的换行符   每个字节!

     

因此,GNU grep不是使用面向行的输入,而是将原始数据读入   一个大缓冲区,使用Boyer-Moore搜索缓冲区,并且仅在   它找到匹配它去寻找边界换行符   (某些命令行选项,如   -n禁用此优化。)

此答案是从here获取的信息的子集。

答案 1 :(得分:34)

增加史蒂夫的优秀答案。

可能并不广为人知,但是当grepping 更长 模式时,grep几乎总是 更快 字符串而不是短字符串,因为在更长的模式中, Boyer-Moore 可以在更长的步幅中向前跳过,以实现更好的 次线性 速度:< / p>

示例:

# after running these twice to ensure apples-to-apples comparison
# (everything is in the buffer cache) 

$ time grep -c 'tg=f_c' 20140910.log
28
0.168u 0.068s 0:00.26

$ time grep -c ' /cc/merchant.json tg=f_c' 20140910.log
28
0.100u 0.056s 0:00.17

较长的形式快35%!

为什么? Boyer-Moore 从模式字符串中构造一个跳过转发表,并且每当出现不匹配时,它会在比较单个字符串之前选择最长的跳过(从最后一个字符到第一个字符串)跳过表中char的输入。

这里a video explaining Boyer Moore(感谢kommradHomer)

另一个常见的误解(对于GNU grep)是fgrepgrep快。 f fgrep中的fgrep并不代表“快速”,它代表的是“固定”状态&#39; (参见手册页),既然两者都是同一个程序,并且都使用 Boyer-Moore ,那么在没有regexp特殊字符的情况下搜索固定字符串时,它们之间的速度没有区别。我使用.的唯一原因是当有正则表达式特殊字符(例如[]*grep -F)时,我不想要它被解释为这样。即使这样,fgrep的便携/标准形式也优于{{1}}。