强制管道中的标准输出行缓冲

q1qsirdb  于 2022-10-17  发布在  Unix
关注(0)|答案(7)|浏览(228)

通常,stdout是行缓冲的。换句话说,只要printf参数以换行符结束,就可以立即打印该行。当使用管道重定向到tee时,这似乎不成立。
我有一个C程序a,它将始终以n结尾的字符串输出到stdout
当它自己运行时(./a),一切都会像预期的那样在正确的时间正确打印。但是,如果通过管道将其传递给tee(./a | tee output.txt),则在退出之前它不会打印任何内容,这就违背了使用tee的目的。
我知道我可以通过在C
程序中的每个打印操作之后添加一个fflush(stdout)来修复它。但有没有更干净、更容易的方法呢?例如,有没有我可以运行的命令来强制stdout进行行缓冲,即使在使用管道时也是如此?

2q5ifsrm

2q5ifsrm1#

你可以试试stdbuf

$ stdbuf --output=L ./a | tee output.txt

手册页的(大)部分:

-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.

不过,请记住这一点:

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的一部分。

kcwpcxri

kcwpcxri2#

尝试unbuffer(man page),它是expect包的一部分。您的系统中可能已经有它了。
在您的例子中,您可以这样使用它:
unbuffer ./a | tee output.txt
-p选项用于管道模式,在这种模式下,unBuffer从stdin读取数据并将其传递给其余参数中的命令。

tvz2xvvm

tvz2xvvm3#

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

setlinebuf(stdout);

这应该会将缓冲更改为“行缓冲”。
如果需要更大的灵活性,可以使用setvbuf。

blmhpbnm

blmhpbnm4#

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

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

请注意,script命令不会传回WRAPPED命令的退出状态。

hmae6n7t

hmae6n7t5#

@处的expect包中的unbuffer命令暂停,直到进一步通知答案不适用于我所呈现的方式。
而不是使用:
./a | unbuffer -p tee output.txt
我不得不使用:
unbuffer -p ./a | tee output.txt
(-p用于管道模式,在该模式下,unBuffer从stdin读取并将其传递给其余参数中的命令)
expect程序包可以安装在:
1.带pacman -S expect的MSYS2
1.配备brew install expect的Mac OS

更新

我最近在一个外壳脚本中遇到了python的缓冲问题(在尝试将时间戳附加到其输出时)。修复方法是通过以下方式将-u标志传递给python
1.run.shpython -u script.py
1.unbuffer -p /bin/bash run.sh 2>&1 | tee /dev/tty | ts '[%Y-%m-%d %H:%M:%S]' >> somefile.txt
1.此命令将在输出上加上时间戳,并同时将其发送到文件和标准输出。
1.moreutils包可以安装ts程序(时间戳)。

更新2

最近,也遇到了grep缓冲输出的问题,当我在grep上使用参数grep --line-buffered时,它停止缓冲输出。

z4iuyo4d

z4iuyo4d6#

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

fykwrbwg

fykwrbwg7#

最好的答案是grep--line-buffer选项,如下所述:
https://unix.stackexchange.com/a/53445/40003

相关问题