inotify + stdout 管道 - 在管道中丢失输出

3

我有一些用于inotify的生成单行事件的代码。

while true; do for i in $(seq 1 100); do touch /tmp/ino/foo$i; sleep 1s; done; rm /tmp/ino/foo*; done

然后我设置了一个小的bash管道来监视那个文件夹,忽略关于ISDIR的事件(也许我可以用inotifywait来做到这一点,但这并不重要):

inotifywait -m -e close /tmp/ino 2>/dev/null | grep -v ISDIR

这样做是可以的,我会看到像/tmp/ino/ CLOSE_WRITE,CLOSE foo57这样的行。

但是如果我在末尾添加一个额外的管道,就没有输出了。为了简单起见,让我们利用grep pattern是自幂的这一事实。

inotifywait -m -e close /tmp/ino 2>/dev/null | grep -v ISDIR | grep -v ISDIR

这不会产生任何输出。我知道我的生成器仍在运行,并且另一个终端中的无管道inotifywait -m -e close /tmp/ino仍在产生输出。

经过一段时间的思考,我认为这可能是缓冲问题(此类问题似乎经常出现)。我将我的管道更改为

inotifywait -m -e close /tmp/ino 2>/dev/null | grep -v ISDIR --line-buffered | grep -v ISDIR

现在我又能够获得输出了,所以问题得到了解决。

然而,我并不真正理解为什么没有强制行缓冲就无法工作。即使有“慢输出”的情况下,我也从未遇到过像grep这样的问题。 但是,在管道中的一些其他程序,要求使用sed -u,并强制我在每个awk语句的末尾添加fflush()

那么,是什么导致了这里的奇怪缓冲,并且我该如何修复它(而不必在手册页面上寻找晦涩的强制行缓冲命令)?

1个回答

2

inotifywait可能存在缓冲。我建议使用stdbuf来解决:

stdbuf -oL inotifywait -m -e close /tmp/ino 2>/dev/null | grep ...

大多数命令都没有这样的问题。这是inotifywait没有正确地遵循unix标准,还是其他原因? - Squidly
1
“大多数命令”?我怀疑。例如,Perl 的文档说:“如果输出是到终端,则 STDOUT 通常是行缓冲的;否则是块缓冲的。”,这可以通过 perl -E 'say "one"; sleep 3; say "two"'perl -E 'say "one"; sleep 3; say "two"' | cat 以及 perl -E '$|=1; say "one"; sleep 3; say "two"' | cat 之间的差异来证明。 - glenn jackman

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