通过两个命令管道 ping 后没有打印
Nothing prints after piping ping through two commands
运行 这个:
ping google.com | grep -o 'PING'
将打印 PING
到终端,所以我假设这意味着 grep 的标准输出被终端捕获。
那么为什么 follow 命令不打印任何东西?终端刚刚挂起:
ping google.com | grep -o 'PING' | grep -o 'IN'
我认为第一个 grep 命令的标准输出将被重定向到第二个 grep 命令的标准输入。然后第二个 grep 的标准输出将被终端捕获并打印。
这似乎是将 ping 替换为 echo 时会发生的情况:
echo 'PING' | grep -o 'PING' | grep -o 'IN'
IN
打印到终端,如我所料。
那么 ping
有什么特别之处可以防止打印任何内容?
你可以试着更有耐心:-)
ping google.com | grep -o 'PING' | grep -o 'IN'
将最终显示输出,但可能需要半小时左右。
在 Unix 下,如果流是终端,则程序启动时传递给程序的标准输出流是 "line-buffered";否则它是完全缓冲的,通常有 8 KB(8,192 个字符)的缓冲区。缓冲意味着输出在内存中累积,直到缓冲区已满,或者在行缓冲流的情况下,直到发送换行符。
当然,程序可以覆盖此设置,而只产生少量输出的程序(如 ping
)通常会使 stdout 行缓冲,而不管它是什么。但是 grep
不会这样做(尽管您可以使用 --line-buffered
命令行选项告诉 Gnu grep 这样做。)
"Pipes"(为实现 |
运算符而创建)不被视为终端。所以中间的 grep
将有一个完全缓冲的输出,这意味着它的输出将被缓冲直到写入 8k 个字符。在您的情况下,这将花费一些时间,因为每行仅包含五个字符(PING
加上一个换行符),并且它们每行生成一次。所以缓冲区将在大约 1640 秒后填满,这将近 28 分钟。
许多 unix 发行版都带有一个名为 stdbuf
的程序,可用于在 运行 程序之前更改标准流的缓冲。 (如果您有 stdbuf
,您可以通过键入 man 1 stdbuf
来了解它是如何工作的。)像 Perl 这样的编程语言通常提供其他机制来调用 stdbuf
标准库函数。 (在 Perl 中,您可以在每次写入后使用内置变量 $|
或 autoflush(BOOL)
io 句柄方法强制刷新。)
当然,当程序成功终止时,所有输出缓冲区都是"flushed"(srnt到它们各自的流)。所以
echo PING | grep -o 'PING' | grep -o 'IN'
会立即输出它唯一的输出行。但是 ping
不会终止,除非您提供计数命令行选项(-c N
;请参阅 man ping
)。因此,如果您需要即时的管道吞吐量,您可能需要修改缓冲行为。
运行 这个:
ping google.com | grep -o 'PING'
将打印 PING
到终端,所以我假设这意味着 grep 的标准输出被终端捕获。
那么为什么 follow 命令不打印任何东西?终端刚刚挂起:
ping google.com | grep -o 'PING' | grep -o 'IN'
我认为第一个 grep 命令的标准输出将被重定向到第二个 grep 命令的标准输入。然后第二个 grep 的标准输出将被终端捕获并打印。
这似乎是将 ping 替换为 echo 时会发生的情况:
echo 'PING' | grep -o 'PING' | grep -o 'IN'
IN
打印到终端,如我所料。
那么 ping
有什么特别之处可以防止打印任何内容?
你可以试着更有耐心:-)
ping google.com | grep -o 'PING' | grep -o 'IN'
将最终显示输出,但可能需要半小时左右。
在 Unix 下,如果流是终端,则程序启动时传递给程序的标准输出流是 "line-buffered";否则它是完全缓冲的,通常有 8 KB(8,192 个字符)的缓冲区。缓冲意味着输出在内存中累积,直到缓冲区已满,或者在行缓冲流的情况下,直到发送换行符。
当然,程序可以覆盖此设置,而只产生少量输出的程序(如 ping
)通常会使 stdout 行缓冲,而不管它是什么。但是 grep
不会这样做(尽管您可以使用 --line-buffered
命令行选项告诉 Gnu grep 这样做。)
"Pipes"(为实现 |
运算符而创建)不被视为终端。所以中间的 grep
将有一个完全缓冲的输出,这意味着它的输出将被缓冲直到写入 8k 个字符。在您的情况下,这将花费一些时间,因为每行仅包含五个字符(PING
加上一个换行符),并且它们每行生成一次。所以缓冲区将在大约 1640 秒后填满,这将近 28 分钟。
许多 unix 发行版都带有一个名为 stdbuf
的程序,可用于在 运行 程序之前更改标准流的缓冲。 (如果您有 stdbuf
,您可以通过键入 man 1 stdbuf
来了解它是如何工作的。)像 Perl 这样的编程语言通常提供其他机制来调用 stdbuf
标准库函数。 (在 Perl 中,您可以在每次写入后使用内置变量 $|
或 autoflush(BOOL)
io 句柄方法强制刷新。)
当然,当程序成功终止时,所有输出缓冲区都是"flushed"(srnt到它们各自的流)。所以
echo PING | grep -o 'PING' | grep -o 'IN'
会立即输出它唯一的输出行。但是 ping
不会终止,除非您提供计数命令行选项(-c N
;请参阅 man ping
)。因此,如果您需要即时的管道吞吐量,您可能需要修改缓冲行为。