优化 GNU grep

优化 GNU grep

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

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

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

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

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

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

答案1

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

虽然看到为什么 1250 个字符串与 90k 个模式的匹配速度如此之慢?关于 GNU 某些版本中的一个错误,grep该错误会使大量正则表达式的速度特别慢。

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

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

awk尽管用or来完成整个事情可能会更简单perl

但是,如果您不需要grep将输出放入不同块的不同文件中,您始终可以这样做:

{
  cat chunk1
  while wget -qO- ...; done # or whatever you use to fetch those chunks
  ...
} | grep -Ef patterns > output

答案2

我无法对所有输入使用 grep,因为它是一个流。我可以积累一大块流并对其使用 grep ...

您知道管道堵塞吗?如果您将某些内容通过管道传递给 grep 并且所有输入都不可用,则 grep 将等待直到可用,然后继续,就好像输入一直存在一样。

$ ( echo a1; echo b1; sleep 5; echo a2 ) | grep 'a.'
a1
a2

编辑:管道如何工作,例如,cmd1 | cmd2两个程序将同时启动,例如它们之间有一个 65,536 字节的“块缓冲区”。当cmd2尝试读取且缓冲区为空时,它将等待可用的块。当cmd1尝试写入并且缓冲区已满时,它将等待直到cmd2读取它。

据我所知,不需要将输入切成块并将它们单独传递给 grep。这已经自动完成了。

EDIT2:grep还应该在流中找到结果后立即打印结果。无需流完成即可获得结果。

答案3

也许你可以“对所有输入使用 grep”?使用nc(netcat)、或通过script或通过其他类似的工具?特别是如果您的模式文件大小可控(例如少于 1000 个正则表达式)。

第一个例子:您可以进行egrep一些流连接:(此处以 为例nc,但其他也可以适用)

prompt:/some/path $ nc somehost someport | egrep -f patternfile | gzip -c - > results.gz

# and while this is running, you can have a look at the growing results.gz:
prompt:/some/otherpath $ tail -f /some/path/results.gz | gzip -c - | less

(注意:您甚至可以:touch /some/path/results.gz在启动nc命令之前,并使用tail -f该(空)文件以免错过任何内容。无论如何,results.gz 将包含您想要捕获的所有内容)

第二个例子:您甚至可以egrep在当前正在运行的 shell 会话上(并显示另一种跟踪进度的方法):

#in 1 terminal:
prompt:/home/userA $ script
Script command is started. The file is typescript.
prompt:/home/userA $ 
 ... doing here whatever you want (start IRC? etc) ...
prompt:/home/userA $ ctrl-d # to end the current script session
Script command is complete. The file is typescript.

#and in another terminal, while you are "doing here whatever you want" :
prompt:/home/somewhere $ tail -f /home/userA/typescript | egrep -f patternfile  | tee /some/place/to/store/results.gz

egrepgrep是, 在大多数系统上的高效版本(请参阅 的一些有趣信息:https://swtch.com/~rsc/regexp/regexp1.html

相关内容