我有一些从 中提取计时信息的不同方法的示例ping -c 10 google.com
。对于其中一些管道,每隔一段时间就会产生一行输出,就像 ping 的输出一样。对于其他输出行,在处理完所有输出行后立即发出所有输出行。对于何时看到第一个行为以及何时看到第二个行为,是否有一个好的规则?
# prints output for each line as soon as it is received
# on OS X and Linux.
ping -c 10 google.com | grep -o 'time=\S*'
# prints output for each line as soon as it is received on OS X
# but not on Linux
# (the output of ping is slightly different so it's $8 on Linux to get the time)
ping -c 10 google.com | awk '{ print $7 }'
# waits until all input is received on OS X and Linux
ping -c 10 google.com | awk -F ':' '{ print $2 }'
# prints output for line as soon as it is received on Linux and OS X
ping -c 10 google.com | sed -e 's/^.*time=\(.*\) .*$/\1/'
# waits for the end of input on OS X and Linux
ping -c 10 google.com | grep -o 'time\S*' | sed -e 's/time=//'
# as a quick check, this prints each line of output immediately
# on OS X and Linux
ping -c 10 google.com | sed -e 's/time=//'
环顾四周后,这似乎只是行缓冲的问题,并且一些标准实用程序在交互使用与非交互使用时表现不同。
答案1
这是关于如何使用这些程序处理缓冲的。
如果您希望 grep 立即输出管道数据,请将其与选项 --line-buffered 一起使用。
ping -c 10 google.com | grep --line-buffered -o 'time\S*' | sed -e 's/time=//'
如果您希望 awk 立即输出管道数据,可以使用选项 -W Interactive。
ping -c 10 google.com | awk -W interactive '{ print $7 }'
您应该阅读这些应用程序的手册页以了解更多信息。
答案2
当涉及的描述符不是 tty 时,此类缓冲由管道完成。某些命令具有特定选项来处理此问题并强制执行交互行为。
处理这个问题的通用方法
您可以使用stdbuf
来自 GNU Coreutils。它管理stdin
、stdout
和的缓冲stderr
。您可以通过将其设置为 来完全禁用它0
,或者通过将其设置为 来使用行缓冲L
:
stdbuf -i0 -o0 -e0 command
stdbuf -oL ping example.com
该命令通过setvbuf()
黑客设置来工作LD_PRELOAD
。如果被调用的命令再次强行调用该函数,stdbuf
可能会无法禁用缓冲。
您还可以使用unbuffer
命令达到基本相同的结果。该命令与默认情况下相关expect
,并且可能不会安装。它基本上可以如下使用:
unbuffer command
命令特定选项
关于特定于命令的缓冲,以下是禁用它的方法:
- GNU
grep
选项禁用缓冲:--line-buffered
- GNU
sed
选项禁用缓冲:-u
awk
当没有控制 tty 时,GNU不缓冲。mawk
,至少是 Debian/Ubuntu 的默认 awk,做输出缓冲。mawk
可能不能使用stdbuf
并提供-Winteractive
禁用缓冲的选项。