将stdout从subprocess.Popen保存到文件,再将更多内容写入文件

时间:2010-07-06 22:59:31

标签: python linux subprocess stdout python-2.4

我正在编写一个python脚本,它使用subprocess.Popen来执行两个程序(来自已编译的C代码),每个程序生成stdout。该脚本获取该输出并将其保存到文件中。因为输出有时足以压倒subprocess.PIPE,导致脚本挂起,所以我将stdout直接发送到日志文件。我想让我的脚本写一些文件的开头和结尾,以及两个subprocess.Popen调用之间。但是,当我查看我的日志文件时,我从脚本写入日志文件的所有内容都在文件顶部,然后是所有可执行文件stdout。如何将添加的文本交错到文件?

def run(cmd, logfile):
    p = subprocess.Popen(cmd, shell=True, universal_newlines=True, stdout=logfile)
    return p

def runTest(path, flags, name):
    log = open(name, "w")
    print >> log, "Calling executable A"
    a_ret = run(path + "executable_a_name" + flags, log)
    print >> log, "Calling executable B"
    b_ret = run(path + "executable_b_name" + flags, log)
    print >> log, "More stuff"
    log.close()

日志文件包含: 调用可执行文件A. 调用可执行文件B. 更多东西 [...来自两个可执行文件的标准输出...]

例如,有没有办法在调用Popen后将A的标准输出到日志?还有一件事可能是相关的:可执行A开始然后挂在B上,在B打印完成后,A然后打印更多东西并完成。

我在RHE Linux上使用Python 2.4。

4 个答案:

答案 0 :(得分:20)

您可以在每个Popen对象上调用.wait()以确保它已完成,然后调用log.flush()。也许是这样的:

def run(cmd, logfile):
    p = subprocess.Popen(cmd, shell=True, universal_newlines=True, stdout=logfile)
    ret_code = p.wait()
    logfile.flush()
    return ret_code

如果需要与外部函数中的Popen对象进行交互,可以将.wait()调用移到那里。

答案 1 :(得分:2)

您需要等到该过程完成后再继续。我还将代码转换为使用更清晰的上下文管理器。

def run(cmd, logfile):
    p = subprocess.Popen(cmd, shell=True, universal_newlines=True, stdout=logfile)
    p.wait()
    return p

def runTest(path, flags, name):
    with open(name, "w") as log:
        print >> log, "Calling executable A"
        a_ret = run(path + "executable_a_name" + flags, log)
        print >> log, "Calling executable B"
        b_ret = run(path + "executable_b_name" + flags, log)
        print >> log, "More stuff"

答案 2 :(得分:2)

我说保持简单。伪代码基本逻辑:

write your start messages to logA
execute A with output to logA
write your in-between messages to logB
execute B with output to logB
write your final messages to logB
when A & B finish, write content of logB to the end of logA
delete logB

答案 3 :(得分:2)

据我所知,A程序等待B执行此操作,A仅在B退出后退出。

如果B可以在没有A运行的情况下启动,那么您可以按相反的顺序启动进程:

from os.path import join as pjoin
from subprocess import Popen

def run_async(cmd, logfile):
    print >>log, "calling", cmd
    p = Popen(cmd, stdout=logfile)
    print >>log, "started", cmd
    return p

def runTest(path, flags, name):
    log = open(name, "w", 1)  # line-buffered
    print >>log, 'calling both processes'
    pb = run_async([pjoin(path, "executable_b_name")] + flags.split(), log)
    pa = run_async([pjoin(path, "executable_a_name")] + flags.split(), log)
    print >>log, 'started both processes'
    pb.wait()
    print >>log, 'process B ended'
    pa.wait()
    print >>log, 'process A ended'
    log.close()

注意:在主进程中调用log.flush()对子进程中的文件缓冲区没有影响。

如果子进程对stdout使用块缓冲,那么你可以尝试使用pexpect, pty, or stdbuf强制它们更快地刷新(它假设进程使用行缓冲,如果以交互方式运行或者它们使用C stdio库进行I / O)。