关于unix:当管道连接到三通时强制线缓冲标准输出

Force line-buffering of stdout when piping to tee

通常,stdout是线路缓冲的。换句话说,只要您的printf参数以换行符结束,您就可以期望该行立即打印。当使用管道重定向到tee时,这似乎不适用。

我有一个C++程序,EDOCX1,3,输出字符串,总是EDCOX1,4终止,到EDCOX1×0。

当它自己运行(./a)时,一切都按预期在正确的时间正确打印。但是,如果我把它放到tee(./a | tee output.txt上),它在退出之前不会打印任何内容,这就破坏了使用tee的目的。

我知道,在C++程序中的每个打印操作之后,我可以通过添加一个EDOCX1 10来修复它。但是有没有一种更清洁、更简单的方法?例如,我是否可以运行一个命令,即使在使用管道时,也会强制stdout进行行缓冲?


你可以试试stdbuf

1
$ stdbuf -o 0 ./a | tee output.txt

(大)手册的一部分:

1
2
3
4
5
6
7
8
9
10
11
12
13
  -i, --input=MODE   adjust standard input stream buffering
  -o, --output=MODE  adjust standard output stream buffering
  -e, --error=MODE   adjust standard error stream buffering

If MODE is 'L' the corresponding stream will be line buffered.
This option is invalid with standard input.

If MODE is '0' the corresponding stream will be unbuffered.

Otherwise MODE is a number which may be followed by one of the following:
KB 1000, K 1024, MB 1000*1000, M 1024*1024, and so on for G, T, P, E, Z, Y.
In this case the corresponding stream will be fully buffered with the buffer
size set to MODE bytes.

不过,请记住:

1
2
3
4
NOTE: If COMMAND adjusts the buffering of its standard streams ('tee' does
for e.g.) then that will override corresponding settings changed by 'stdbuf'.
Also some filters (like 'dd' and 'cat' etc.) dont use streams for I/O,
and are thus unaffected by 'stdbuf' settings.

你不是在tee上运行stdbuf,而是在a上运行,所以这不会影响你,除非你在a的源中设置了a流的缓冲。

另外,stdbuf不是posix,而是gnu coreutils的一部分。


尝试unbuffer,它是expect包的一部分。您的系统中可能已经有了它。

在您的情况下,您可以这样使用它:

./a | unbuffer -p tee output.txt

(-p用于管道模式,其中unbuffer从stdin读取数据并在其余参数中将其传递给命令)


您还可以尝试使用script命令(它应该强制执行到管道的行缓冲输出)在伪终端中执行命令!

1
2
script -q /dev/null ./a | tee output.txt     # Mac OS X, FreeBSD
script -c"./a" /dev/null | tee output.txt   # Linux

请注意,script命令不会传播包装命令的退出状态。


您可以使用stdio.h中的setlinebuf。

1
setlinebuf(stdout);

这应该将缓冲改为"线路缓冲"。

如果您需要更多的灵活性,可以使用setvbuf。


如果您使用C++流类,则每个EDCOX1(11)都是隐式刷新。使用C型打印,我认为您建议的方法(fflush()是唯一的方法。