Bash的tail命令和多个管道

5
我目前遇到了一个与命令有关的问题。
while sleep 0.3; do echo "1"; done | tail -n +3 | grep --line-buffered "1"

我想要一个看起来像这样的输出:
[nothing during 0.6s]
1
1
...

但有:

[nothing forever]

我发现了这个问题并阅读了这篇博客文章,但由于--line-buffered选项已设置为grep,因此我认为这不是一个缓冲问题。我的研究没有引导我找到其他解决方案,希望我没有漏掉什么明显的东西。
如果有必要,我正在使用zsh 5.7.1(x86_64-pc-linux-gnu)

1
tail 命令的输出被缓存。 - Barmar
1
「--line-buffered」选项只有在将grep的输出管道传送给需要立即查看它的内容时才有用。因为你没有将该输出进行管道传输,所以这里并不有用。 - Barmar
2个回答

6

正如Barmar在评论中提到的那样,这个问题被吞没在一个4KB stdio缓冲区中。您可以使用unbuffer -p来避免这种情况:

while sleep 0.3; do echo "1"; done | unbuffer -p tail -n +3 | grep 1

或者你也可以在行缓冲模式下使用stdbuf

while sleep 0.3; do echo "1"; done | stdbuf -oL tail -n +3 | grep 1

1
它解决了我的问题。我应该彻底阅读博客文章,而不是快速搜索其中的信息。谢谢! - Adrien Suau
澄清一下,数据保存在4k的glibc stdio输出缓冲区中,而不是64k的管道缓冲区中。 - that other guy
@thatotherguy 谢谢,重新表达。 - Jeff Bowman

1
根据实际情况,您可能可以通过使用单个更强大的工具(如awk)来避免由tailgrep的管道引起的问题。请注意保留HTML标签。
while sleep 0.3; do echo "1"; done | awk 'NR > 2 && /1/'

当然,如果您需要将awk的输出导入其他地方,那么您将面临同样的问题。但是,如果您的awk版本支持它,您可以明确地刷新输出:

while sleep 0.3; do echo "1"; done | awk 'NR > 2 && /1/ {print $0; fflush()}' | | while read x; do echo "read '$x'"; done

...或者使用unbuffer -pstdbuf -oLawk上(参见@JeffBowman的答案),如果你有这些命令(我没有,所以我无法测试)。


我在问题中写的命令是简化的,主要是因为我使用的一些工具是非标准的,我不想让人们安装额外的工具来测试命令。整个命令需要4个管道,最后一个是while read ...命令。尽管如此,这可能对其他人来说是一个有效的解决方案,谢谢! - Adrien Suau
@Nelimee 哈哈,我找到了一种方法在 awk 中使用另一个管道使其工作。可能对你的情况仍然不相关,但对其他人可能有用。 - Gordon Davisson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接