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

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

我能够成功运行此命令:

tail -f my_file.txt | grep foo

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

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

tail -f my_file.txt | grep foo | grep bar

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

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

答案1

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

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

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

tail -f my_file.txt | grep --line-buffered foo | grep bar

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

关闭管道中的缓冲缓冲问题的通用解决方案。


在这个有两个 grep 的特殊情况下,您可以使用单个 AWK 来代替,如 Stéphane Chazelas 在评论中提到的那样:

tail -f my_file.txt | awk '/foo/ && /bar/'

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

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

... | grep -E -e 'foo.*bar|bar.*foo'

反而。

答案2

从布尔的角度来看,你似乎在期待或者酒吧与你的 grep ,但从你所做的方式来看,你应该期望酒吧-- 唯一会被 grep 的行酒吧是那些通过了首先是 grep 。

如果您希望 foo/bar 在标准输出上弹出,您需要使用:

尾-f my_file.txt | grep“foo|bar”

您可以添加任意多个关键字“pretty|much|like|这些”,只是不要忘记引号。 (或使用多个\|未加引号的\|术语

第二点:因为它是尾部-f(如下)your_file.txt 也可能在特定时间没有附加包含两个关键字的行,通常最好剪切已知具有您期望的内容的该文件的共享:

tail -n 500 my_file.txt > my_sample.txt

从那里您可以尝试使用已知文本进行任何您喜欢的 grep 操作。 (我猜最后 500 行就足够了,根据需要进行调整。)

相关内容