26

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

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

4 回答 4

25

您可以在每个 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() 调用移到那里。

于 2010-07-06T23:03:52.600 回答
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"
于 2010-07-06T23:04:42.027 回答
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
于 2010-07-08T04:27:01.917 回答
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 或 stdbuf强制它们更快地刷新(假设进程在交互运行时使用行缓冲,或者它们使用 C stdio 库进行 I/O) .

于 2012-11-22T13:57:36.767 回答