以下内容在 bash 中不会产生任何结果:
while true ; do upower -d ; sleep 1 ; done | grep percentage | uniq
我发现这个链中最后一个甚至倒数第二个程序是什么并不重要。倒数第二个程序总是产生预期的输出,而最后一个程序总是无法产生任何结果。
( while ... done )
如果我将 while 循环包装在子 shell 中(通过),或者将除最后一个命令之外的所有内容包装在子 shell 中并通过管道传输到最后一个命令,这似乎也并不重要。
我对这种行为深感困惑。
我的直觉告诉我...
...由于阻塞读取和写入而创建的链中存在某种 I/O 死锁,而且 while 循环并不总是产生输出。但是,另一方面,我以前已经做过很多次这样的事情了,没有任何问题。另外,如果是这样的话,那while循环和下一个命令之间不就存在问题了吗?所以我很困惑。如果其他人无法重现,将提供 bash 版本信息。
万一它不是立即显而易见的......
这行代码的要点是打印电池百分比的每次变化,但只打印新的电池电量。它使用轮询。我想我只需运行就能得到相同的行为
upower --monitor-detail | grep percentage | uniq
但这是一次性的事情,我并没有打算在这上面花费超过 5 秒钟的思考,直到上面的方法开始失败。这时候它就变成了一个有趣的问题。另外,我不知道监视器详细信息是否只是在幕后进行轮询(而且我没有运行 strace 来检查)。
编辑:显然,上面的--monitor-detail
版本也没有产生任何东西(或者,至少看起来是这样。轮询/更新频率相当低,所以我可能没有等待足够长的时间。虽然我知道我为原始问题等待了足够长的时间)。现在我非常非常困惑。我想我应该运行那个 strace 毕竟......
答案1
您应该使用grep --line-buffered percentage
,否则标准输出缓冲区将需要很长时间才能grep
被其输出填充。
答案2
除了 Marco d'Itri 的答案之外,并非每个工具都支持自定义缓冲。如果您正在运行的工具没有这样做,或者您想使用自定义缓冲区大小来运行它,您可以使用stdbuf
覆盖工具的缓冲行为;例如,在这种情况下,强制输出进行行缓冲:
while true ; do upower -d ; sleep 1 ; done | stdbuf -oL grep 'percentage' | uniq
强制输出不缓冲:
while true ; do upower -d ; sleep 1 ; done | stdbuf -o0 grep 'percentage' | uniq
强制输出以 512 B 为块进行缓冲:
while true ; do upower -d ; sleep 1 ; done | stdbuf -o512 grep 'percentage' | uniq
您可以添加 K、M、G、[...] 来指定以 KB、MB、GB、[...] 为单位的输出:
while true ; do upower -d ; sleep 1 ; done | stdbuf -o512K grep 'percentage' | uniq
答案3
使用任何 POSIX,sed
您都可以使用 rite 命令实现行缓冲输出w
。
while sleep 1
do upower -d
done |
sed -n /percentage/w\ /dev/fd/1 |
uniq
...将在支持/dev/fd/[num]
链接的系统上工作(例如几乎任何 Linux 系统)。
但你可以这样做:
while sleep 1
do upower -d
done |
sed '/percentage/!d;H;x
/^\(.*\)\n\1$/d;g'
上面应该这样做 - 它只是将uniq
和的功能打包grep
到一个小sed
脚本中。