10

我有一个将输出打印到标准输出的封闭源程序。我需要解析输出。所以我使用 dup2 将输出重定向到一个 fifo(我可以从中读取分叉和执行二进制文件的父进程),然后执行程序。问题是文件中的 fprintf 调用被缓冲,因为它现在正在写入文件。

在调用 exec 之前,我尝试在标准输出上使用 _IONBF 调用 setvbuf。但问题仍然存在。

为什么 setvbuf 对我没有帮助?

我怎样才能强制输出被刷新?

4

3 回答 3

6

setvbuf()没有区别,因为它改变了部分 C 运行时库的状态,而不是操作系统的一部分。当新进程开始运行时,它的 C 运行时库将被重新初始化(如果它完全使用 CRT!)

我听说解决此问题的唯一方法是以某种方式伪造进程的终端。这是因为大多数 CRT 库默认情况下只执行行缓冲,如果它们认为它们连接到交互式终端(在 Unix 世界中:如果isatty()在文件描述符上返回 true),否则它们将缓冲在更大的块中(通常是 8Kb 左右)。

这个实用程序看起来是一个很好的起点。(从对 Trick an application 的评论中借用认为它的 stdin 是交互式的,而不是具有其他有用信息的 pipe 。)

于 2010-01-13T10:38:11.430 回答
2

我猜你的程序中有这样的东西(你可以为你的测试重现这个,我在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.expectexpect如果未安装,请为您的发行版安装)

#! /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
于 2010-01-13T14:24:49.873 回答
2

unbuffer工具可以帮助解决此问题:

expect-dev它是 ubuntu的一部分,可以使用

sudo apt-get install expect-dev

使用它类型:

unbuffer ls > log.txt
于 2013-06-06T10:21:24.300 回答