我有一个将输出打印到标准输出的封闭源程序。我需要解析输出。所以我使用 dup2 将输出重定向到一个 fifo(我可以从中读取分叉和执行二进制文件的父进程),然后执行程序。问题是文件中的 fprintf 调用被缓冲,因为它现在正在写入文件。
在调用 exec 之前,我尝试在标准输出上使用 _IONBF 调用 setvbuf。但问题仍然存在。
为什么 setvbuf 对我没有帮助?
我怎样才能强制输出被刷新?
setvbuf()
没有区别,因为它改变了部分 C 运行时库的状态,而不是操作系统的一部分。当新进程开始运行时,它的 C 运行时库将被重新初始化(如果它完全使用 CRT!)
我听说解决此问题的唯一方法是以某种方式伪造进程的终端。这是因为大多数 CRT 库默认情况下只执行行缓冲,如果它们认为它们连接到交互式终端(在 Unix 世界中:如果isatty()
在文件描述符上返回 true),否则它们将缓冲在更大的块中(通常是 8Kb 左右)。
这个实用程序看起来是一个很好的起点。(从对 Trick an application 的评论中借用认为它的 stdin 是交互式的,而不是具有其他有用信息的 pipe 。)
我猜你的程序中有这样的东西(你可以为你的测试重现这个,我在isatty
这里调用它)
#include <stdio.h>
#include <unistd.h>
const char* m1 = "%d: %s a TTY\n";
void isTty(FILE* f) {
int fno = fileno(f);
printf(m1, fno, (isatty(fno)) ? "is" : "is NOT");
}
int main(int argc, char* argv[]) {
isTty(stdin);
isTty(stdout);
}
例如,如果你运行它
$ ./isatty
0: is a TTY
1: is a TTY
$ ./isatty > isatty.out
$ cat isatty.out
0: is a TTY
1: is NOT a TTY
$ ./isatty > isatty.out < /dev/null
$ cat isatty.out
0: is NOT a TTY
1: is NOT a TTY
现在,如果您创建一个expect
脚本isatty.expect
(expect
如果未安装,请为您的发行版安装)
#! /usr/bin/expect -f
spawn "./isatty"
expect
并运行它
$ ./isatty.expect
spawn ./isatty
0: is a TTY
1: is a TTY
或者
$ ./isatty.expect > isatty.out
$ cat isatty.out
spawn ./isatty
0: is a TTY
1: is a TTY
该unbuffer
工具可以帮助解决此问题:
expect-dev
它是 ubuntu的一部分,可以使用
sudo apt-get install expect-dev
使用它类型:
unbuffer ls > log.txt