150

通常,stdout是行缓冲的。换句话说,只要您的printf论点以换行符结尾,您就可以期望该行会立即打印出来。当使用管道重定向到tee.

我有一个 C++ 程序,a它输出字符串,总是\n终止,到stdout.

当它自己运行时 ( ./a),一切都按预期在正确的时间正确打印。但是,如果我将它通过管道传输到tee( ./a | tee output.txt),它在退出之前不会打印任何内容,这违背了使用tee.

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

4

6 回答 6

153

你可以试试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.

你没有在运行stdbuftee你正在运行它a,所以这不应该影响你,除非你在' 源中设置a' 流的缓冲。a

此外,stdbuf不是POSIX,而是 GNU-coreutils 的一部分。

于 2012-07-05T02:10:44.630 回答
80

试试unbuffer哪个是expect包装的一部分。您可能已经在系统上安装了它。

在你的情况下,你会像这样使用它:

./a | unbuffer -p tee output.txt

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

于 2012-07-05T02:50:35.110 回答
33

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

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

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

于 2012-07-05T17:12:25.500 回答
30

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

setlinebuf(stdout);

这应该将缓冲更改为“行缓冲”。

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

于 2015-05-14T14:46:50.233 回答
5

@Paused包中的命令unbuffer直到另行通知答案对我来说并没有按照它的呈现方式工作。expect

而不是使用:

./a | unbuffer -p tee output.txt

我不得不使用:

unbuffer -p ./a | tee output.txt

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

expect软件包可以安装在:

  1. MSYS2 与pacman -S expect
  2. Mac 操作系统brew install expect

更新

我最近python在 shell 脚本内部遇到了缓冲问题(尝试将时间戳附加到其输出时)。修复方法是将-u标志传递给python这种方式:

  1. run.shpython -u script.py
  2. unbuffer -p /bin/bash run.sh 2>&1 | tee /dev/tty | ts '[%Y-%m-%d %H:%M:%S]' >> somefile.txt
  3. 此命令将在输出上放置一个时间戳并将其同时发送到文件和标准输出。
  4. ts程序(时间戳)可以随moreutils包一起安装。

更新 2

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

于 2020-08-15T12:11:33.750 回答
2

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

于 2012-07-05T03:12:29.897 回答