为什么我不能在 tail 之后执行两次 grep 操作?

Ram*_*hum 12 grep pipe tail

我能够成功运行此命令:

tail -f my_file.txt | grep foo
Run Code Online (Sandbox Code Playgroud)

它只显示带有字符串 的行foo,并且一直显示它们。

但是当我运行这个命令时:

tail -f my_file.txt | grep foo | grep bar
Run Code Online (Sandbox Code Playgroud)

它不显示任何行,即使有些行同时包含foobar

我知道有一个在一次grep调用中使用多种模式的解决方案,但我想知道为什么这条线失败了。

ilk*_*chu 27

这是因为 C 运行时库的默认行为是缓冲对 stdout 的写入,直到写入完整的数据块(通常是几千字节),除非 stdout 连接到终端。

\n

一旦中间的 grep 打印了一个完整的块,您就会得到输出,但是您必须再次等待下一个块填充,依此类推。这是对吞吐量的优化,当左侧命令只执行某些任务并终止而不是等待某些操作时,效果会更好。

\n

GNU grep 可以选择--line-buffered关闭该缓冲,因此这应该可以更好地工作:

\n
tail -f my_file.txt | grep --line-buffered foo | grep bar\n
Run Code Online (Sandbox Code Playgroud)\n

最后一个grep打印到终端,因此默认情况下它是行缓冲的,不需要选项。

\n

有关缓冲问题的通用解决方案,请参阅 关闭管道中的缓冲。

\n
\n

在这个有两个 grep 的特殊情况下,您可以使用例如单个 AWK,而不是像评论中提到的 St\xc3\xa9phane Chazelas 那样:

\n
tail -f my_file.txt | awk \'/foo/ && /bar/\'\n
Run Code Online (Sandbox Code Playgroud)\n

(顺便说一句,你也可以做类似的事情,用但没有 来awk \'/foo/ && !/bar/\'捕捉线条。)foobar

\n

在 grep 中做同样的事情会更困难,因为grep -e foo -e bar匹配任何包含 foo bar行。你需要类似的东西

\n
... |\xc2\xa0grep -E -e \'foo.*bar|bar.*foo\'\n
Run Code Online (Sandbox Code Playgroud)\n

反而。

\n