运行此:
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
有什么特别之处可以防止打印任何内容?
答案 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
)。因此,如果您需要立即管道吞吐量,则可能需要修改缓冲行为。