立即在管道中处理“ping”的每一行输出

立即在管道中处理“ping”的每一行输出

我有一些从 中提取计时信息的不同方法的示例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。它管理stdinstdout和的缓冲stderr。您可以通过将其设置为 来完全禁用它0,或者通过将其设置为 来使用行缓冲L

stdbuf -i0 -o0 -e0 command
stdbuf -oL ping example.com

该命令通过setvbuf()黑客设置来工作LD_PRELOAD。如果被调用的命令再次强行调用该函数,stdbuf可能会无法禁用缓冲。

您还可以使用unbuffer命令达到基本相同的结果。该命令与默认情况下相关expect,并且可能不会安装。它基本上可以如下使用:

unbuffer command

命令特定选项

关于特定于命令的缓冲,以下是禁用它的方法:

  • GNUgrep选项禁用缓冲:--line-buffered
  • GNUsed选项禁用缓冲:-u
  • awk当没有控制 tty 时,GNU不缓冲。
  • mawk,至少是 Debian/Ubuntu 的默认 awk,输出缓冲。mawk 可能不能使用stdbuf并提供-Winteractive禁用缓冲的选项。

相关内容