我正在编写一个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。
答案 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)。