如何关闭管道中的标准输出缓冲?

如何关闭管道中的标准输出缓冲?

我有一个调用两个命令的脚本:

long_running_command | print_progress

印刷品long_running_command取得了进展,但我对此不满意。我用来print_progress让它变得更好(即,我在一行中打印进度)。

问题:将管道连接到 stdout 也会激活 4K 缓冲区,因此漂亮的打印程序什么也得不到......什么都没有......什么都没有......一大堆...:)

如何禁用4K缓冲区long_running_command(不,我没有源代码)?

答案1

给这只猫剥皮的另一种方法是使用stdbuf程序,它是 GNU Coreutils 的一部分(FreeBSD 也有自己的)。

stdbuf -i0 -o0 -e0 command

这将完全关闭输入、输出和错误的缓冲。对于某些应用程序,出于性能原因,行缓冲可能更适合:

stdbuf -oL -eL command

请注意,它仅适用于动态链接应用程序的stdio缓冲(printf()fputs()...),并且仅当该应用程序本身不调整其标准流的缓冲时,尽管这应该涵盖大多数应用程序。

答案2

您可以使用unbuffer命令(作为expect包),例如

unbuffer long_running_command | print_progress

unbuffer通过伪终端 (pty)连接long_running_command,这使得系统将其视为交互式进程,因此不使用管道中的 4-kiB 缓冲,而这可能是导致延迟的原因。

对于较长的管道,您可能必须取消缓冲每个命令(最后一个命令除外),例如

unbuffer x | unbuffer -p y | z

答案3

对于grepsedawk可以强制输出进行行缓冲。您可以使用:

grep --line-buffered

强制输出进行行缓冲。默认情况下,当标准输出是终端时,输出是行缓冲的,否则是块缓冲的。

sed -u

使输出行缓冲。

请参阅此页面了解更多信息: http://www.perkin.org.uk/posts/how-to-fix-stdio-buffering.html

答案4

如果当输出未到达终端时 libc 修改其缓冲/刷新出现问题,您应该尝试索卡特。您可以在几乎任何类型的 I/O 机制之间创建双向流。其中之一是与伪 tty 对话的分叉程序。

 socat EXEC:long_running_command,pty,ctty STDIO 

它的作用是

  • 创建一个伪 tty
  • fork long_running_command 并将 pty 的从属端作为 stdin/stdout
  • 在pty的主端和第二个地址(这里是STDIO)之间建立双向流

如果这给出了与 相同的输出long_running_command,那么您可以继续使用管道。

编辑:哇没有看到无缓冲的答案!好吧,socat 无论如何都是一个很棒的工具,所以我可能会留下这个答案

相关内容