管道ping两个命令后没有打印任何内容

时间:2017-12-02 20:48:56

标签: bash pipe ping

运行此:

ping google.com | grep -o 'PING'

PING打印到终端,所以我认为这意味着终端捕获了grep的stdout。

那么为什么跟随命令不打印任何东西?终端只是挂起:

ping google.com | grep -o 'PING' | grep -o 'IN'

我认为第一个grep命令的stdout会被重定向到第二个grep的stdin。然后终端捕获第二个grep的stdout并打印出来。

如果将ping替换为echo,那么这似乎就会发生:

echo 'PING' | grep -o 'PING' | grep -o 'IN'
正如我所料,

IN被打印到终端。

那么ping有什么特别之处可以防止打印任何内容?

1 个答案:

答案 0 :(得分:2)

你可以尝试更耐心:-)

ping google.com | grep -o 'PING' | grep -o 'IN'

最终显示输出,但可能需要半个小时左右。

在Unix下,启动时传递给程序的标准输出流是"行缓冲"如果流是终端;否则它是完全缓冲的,通常使用8千字节(8,192个字符)的缓冲区。缓冲意味着输出在内存中累积,直到缓冲区已满,或者在行缓冲流的情况下,直到发送换行符为止。

当然,程序可以覆盖此设置,只产生少量输出的程序(如ping)通常会使stdout行缓冲,无论它是什么。但是grep没有这样做(尽管你可以通过使用--line-buffered命令行选项告诉Gnu grep这样做。)

"管道" (为实现|运算符而创建)不被视为终端。因此,中间的grep将具有完全缓冲的输出,这意味着它的输出将被缓冲,直到写入8k个字符。在您的情况下需要一段时间,因为每行只包含五个字符(PING加一个换行符),并且它们每秒产生一次。所以缓冲区将在大约1640秒后填满,这几乎是28分钟。

许多unix发行版附带了一个名为stdbuf的程序,可用于在运行程序之前更改标准流的缓冲。 (如果你有stdbuf,你可以通过输入man 1 stdbuf来了解它是如何工作的。)像Perl这样的编程语言通常提供其他机制来调用stdbuf标准库函数。 (在Perl中,您可以使用内置变量$|autoflush(BOOL) io句柄方法在每次写入后强制刷新。)

当然,当一个程序成功终止时,所有输出缓冲区都会被刷新" (srnt到各自的溪流)。所以

echo PING | grep -o 'PING' | grep -o 'IN'

将立即输出其唯一的输出行。但除非您提供计数命令行选项ping,否则-c N不会终止;请参阅man ping)。因此,如果您需要立即管道吞吐量,则可能需要修改缓冲行为。