我在 Ubuntu 上进入了一个有趣的状态。下面的步骤对其进行了最好的描述。
用一根管道,我看到了我所期望的
# In shell A
tail -f foo.log | grep aaa
# In shell B
echo aaa >> foo.log
# Shell A prints out `aaa`
但是有多个管道我什么也看不到
# In shell A
tail -f foo.log | grep aaa | grep bbb
# In shell B
echo aaa bbb >> foo.log
# Nothing ever prints in shell A
但如果我只是回声,它就可以正常工作。
echo 'aaa bbb' | grep aaa | grep bbb
这是我创建最小复制的尝试——我最初遇到的问题是尝试从 adb logcat(Android 开发工具)发送日志。我也尝试过 zsh、bash 和 fish。
我认为它与我的 inotify 观察者限制有关,但碰撞它并没有改变任何东西。
这是因为管道中的缓冲,通常不关心行并且可以累积数据。
我认为
tail -f
单独使用行缓冲;最后grep
写入 tty,因此它也使用行缓冲。因此,您的第一个示例有效。但
grep
在中间是不同的,您需要通过强制行缓冲或禁用缓冲来调整其行为。波纹管命令将按您的预期工作。如果您
grep
支持--line-buffered
(在 Ubuntu 中支持):更通用的解决方案(它们将与除 以外的许多过滤器一起使用
grep
):man 1 grep
有关详细信息和怪癖,请参阅man 1 unbuffer
和man 1 stdbuf
。笔记:
grep --line-buffered
,unbuffer
并且stdbuf
未由 POSIX 指定)。grep --line-buffered
那么它应该是你的选择。使用额外的工具没有意义。unbuffer
并stdbuf
以完全不同的方式工作。stdbuf
,行缓冲 (-oL
) 应该优于无缓冲 (-o0
),因为grep
写入另一个文件,它的行为将与另一个grep
. 在这种情况下,如果您希望行立即出现在最终文件中,那么您还应该修改最后一个grep
.fish
中,如果grep
是一个包装函数,您可能无法通过 获得所需的行为--line-buffered
。使用command grep --line-buffered
. 看到这个问题:Output pipe waits for EOF infish
.旁注:(
tail foo.log | grep aaa | grep bbb
即tail
没有-f
)不会导致问题,因为tail
存在。退出时tail
,第一个grep
检测到 EOF,刷新其缓冲区并退出,然后第二个grep
执行相同操作。