【问题标题】:Getting another program's output as input on the fly即时获取另一个程序的输出作为输入
【发布时间】:2010-11-27 09:04:26
【问题描述】:

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

$ c_program | python_program.py

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

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

我该如何解决这个问题?

【问题讨论】:

  • 你说的输出是多少?涉及缓冲区,因此 4K 以下的任何内容都将始终是一个单一的东西。
  • 没有办法决定何时刷新缓冲区吗?

标签: python c linux bash stdio


【解决方案1】:

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

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

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

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

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

【讨论】:

  • 非常感谢。这有助于我在 srcds_linux 中编写重启程序。我只是把它作为插件放到那个游戏服务器中,瞧..标准输出是成行的,而不是 4k 块。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

      您可能想尝试flushcpp 程序中的标准输出流。

      【讨论】:

        【解决方案5】:

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

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

        $ shelloid 'cpp_program | python_program.py'

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

        【讨论】:

          【解决方案6】:

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

          将你的 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"
          

          【讨论】:

          • 很遗憾,这行不通。问题主要在于 C 程序的输出是缓冲的,而您在 Python 程序中无法做任何事情来影响它。您必须修复 C 程序,使其输出即使在输出到管道时也不会被缓冲。
          猜你喜欢
          • 2015-08-31
          • 2010-10-02
          • 2011-08-28
          • 1970-01-01
          • 2015-01-01
          • 2016-09-27
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多