优化 GNU grep

ber*_*erg 8 grep

我将 egrep ( grep -E) 与 PATTERN 文件一起使用。( -f path/to/file).

这是在文本流的无限循环中完成的。这意味着我无法一次累积并将所有输入传递给 grep(如*.log)。

有没有办法让 grep “保存”它从 PATTERN 文件构建的 NFA 以供下次运行使用?

我已经搜索过谷歌并阅读了文档,但没有运气。

我会试着多解释一下。我需要使用正则表达式来定位固定数量的字符串(这不是问题的一部分,但可以随意提出其他建议),例如 IP 地址、域等。搜索是在来自互联网的提要上完成的。您可以将其视为文本流。我不能grep在所有输入上使用,因为它是一个流。我可以累积一大块流并grep在其上使用(因此不在grep每一行上使用),但这也是有限的(假设为 30 秒)。

我知道grep正在从其所有模式(在我的情况下是从文件)构建 NFA。所以我的问题是:我可以告诉grep为下次运行保存该 NFA,因为它不会改变吗?这将节省我每次构建 NFA 的时间。

Sté*_*las 14

不,没有这样的事情。一般来说,启动grep(fork 一个新进程、加载可执行文件、共享库、动态链接...)的成本会比编译正则表达式要大得多,所以这种优化没有多大意义。

虽然看到为什么将 1250 个字符串与 90k 模式匹配这么慢?关于某些版本的 GNUgrep中的一个错误,该错误会使大量正则表达式变得特别慢。

可能在这里,您可以grep通过将块提供给同一个grep实例来避免多次运行,例如将其用作协同进程并使用标记来检测结束。使用zsh和 GNUgrep以及awkmawk以下之外的其他实现:

coproc grep -E -f patterns -e '^@@MARKER@@$' --line-buffered
process_chunk() {
  { cat; echo @@MARKER@@; } >&p & awk '$0 == "@@MARKER@@"{exit};1' <&p
}
process_chunk < chunk1 > chunk1.grepped
process_chunk < chunk2 > chunk2.grepped
Run Code Online (Sandbox Code Playgroud)

虽然用awkperl代替做整个事情可能更简单。

但是,如果您不需要将grep输出放入不同块的不同文件中,您可以随时执行以下操作:

{
  cat chunk1
  while wget -qO- ...; done # or whatever you use to fetch those chunks
  ...
} | grep -Ef patterns > output
Run Code Online (Sandbox Code Playgroud)

  • @DmitryGrigoryev,是的,很可能,仍然需要在进程地址空间中映射并进行链接编辑。更像是加载和解析语言环境数据、解析选项、环境……关键是 regcomp() 的成本在所有这些开销中被稀释了。优化时要做的第一件事是首先避免运行多个 grep。 (2认同)