我有两个以这种方式使用的程序:
$ c_program | python_program.py
c_program 使用打印一些东西printf(),python_program.py 使用读取sys.stdin.readline()
我想让 python_program.py 在打印时立即处理 c_program 的输出,以便它可以打印自己的当前输出。不幸的是,python_program.py 只有在 c_program 结束后才能得到它的输入。
我该如何解决这个问题?
只需在 C 程序的开头(在执行任何输出之前)将 stdout 设置为行缓冲,如下所示:
#include <stdio.h>
setvbuf(stdout, NULL, _IOLBF, 0);
或者
#include <stdio.h>
setlinebuf(stdout);
任何一个都可以在 Linux 上运行,但setvbuf它是 C 标准的一部分,因此可以在更多系统上运行。
默认情况下,stdout 将为管道或文件进行块缓冲,或为终端缓冲行。由于在这种情况下 stdout 是一个管道,因此默认值将是块缓冲的。如果它是块缓冲的,那么缓冲区将在它满时被刷新,或者当你调用fflush(stdout). 如果它是行缓冲的,那么它将在每行之后自动刷新。
您需要的是让您的 C 程序在每一行之后调用 fflush(stdout)。例如,使用 GNU grep 工具,您可以调用选项“--line-buffered”,这会导致此行为。请参阅fflush。
如果您可以修改您的 C 程序,那么您已经收到了答案,但我想我会为那些不能/不会修改代码的人提供一个解决方案。
expect有一个名为unbuffer的示例脚本可以解决问题。
您可能想尝试flush在 cpp 程序中输入标准输出流。
所有的 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
好的,这听起来可能很愚蠢,但它可能会起作用:
将您的 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"