11

我有两个以这种方式使用的程序:

$ c_program | python_program.py

c_program 使用打印一些东西printf(),python_program.py 使用读取sys.stdin.readline()

我想让 python_program.py 在打印时立即处理 c_program 的输出,以便它可以打印自己的当前输出。不幸的是,python_program.py 只有在 c_program 结束后才能得到它的输入。

我该如何解决这个问题?

4

6 回答 6

18

只需在 C 程序的开头(在执行任何输出之前)将 stdout 设置为行缓冲,如下所示:

#include <stdio.h>
setvbuf(stdout, NULL, _IOLBF, 0);

或者

#include <stdio.h>
setlinebuf(stdout);

任何一个都可以在 Linux 上运行,但setvbuf它是 C 标准的一部分,因此可以在更多系统上运行。

默认情况下,stdout 将为管道或文件进行块缓冲,或为终端缓冲行。由于在这种情况下 stdout 是一个管道,因此默认值将是块缓冲的。如果它是块缓冲的,那么缓冲区将在它满时被刷新,或者当你调用fflush(stdout). 如果它是行缓冲的,那么它将在每行之后自动刷新。

于 2009-09-11T03:27:43.447 回答
9

您需要的是让您的 C 程序在每一行之后调用 fflush(stdout)。例如,使用 GNU grep 工具,您可以调用选项“--line-buffered”,这会导致此行为。请参阅fflush

于 2009-09-11T02:43:34.973 回答
7

如果您可以修改您的 C 程序,那么您已经收到了答案,但我想我会为那些不能/不会修改代码的人提供一个解决方案。

expect有一个名为unbuffer的示例脚本可以解决问题。

于 2009-09-11T04:51:18.913 回答
2

您可能想尝试flush在 cpp 程序中输入标准输出流。

于 2009-09-11T02:40:18.177 回答
1

所有的 Unix shell(据我所知)都通过 pty 以外的其他方式实现 shell 管道(通常,它们使用 Unix 管道!-);因此,C/C++ 运行时库cpp_program将知道它的输出不是终端,因此它将缓冲输出(一次几 KB 的块)。除非您编写自己的 shell(或 semiquasimaybeshelloid)来通过 pyt 实现管道,否则我相信没有办法使用管道符号来做您需要的事情。

有问题的“shelloid”可能是用 Python(或 C、Tcl 或...)编写的,使用pty标准库的模块或基于它的更高级别的抽象,例如pexpect,事实上要通过“基于 pty 的管道”连接的两个程序是用 C++ 编写的,而 Python 则无关紧要。关键思想是欺骗管道左侧的程序,使其相信其 stdout 是一个终端(这就是为什么 pty 必须是技巧的根源)以欺骗其运行时库使其不缓冲输出。一旦你编写了这样一个 shelloid,你会用一些语法来调用它,比如:

$ shelloid 'cpp_program | python_program.py'

当然,通过写下它必须作为子进程python_program产生的知识并欺骗它相信它的 stdout 是一个终端(即,然后直接使用例如)来提供“点解决方案”会更容易。但是,如果您有一百万种这样的情况,您想破坏由系统提供的 C 运行时库执行的正常缓冲,或者在很多情况下您想重用现有的过滤器等,那么编写实际上可能更可取。cpp_programpython_programpexpectshelloid

于 2009-09-11T02:35:11.980 回答
-1

好的,这听起来可能很愚蠢,但它可能会起作用:

将您的 pgm 输出到文件

$ c_program >> ./out.log

开发一个从tail命令读取的python程序

import os

tailoutput = os.popen("tail -n 0 -f ./out.log")

try:
    while 1:
        line = tailoutput.readline()
        if len(line) == 0:
            break

        #do the rest of your things here
        print line

except KeyboardInterrupt:
        print "Quitting \n"
于 2009-09-11T02:58:54.543 回答