关于python:将stdout从subprocess.Popen保存到文件中,以及向文件中写入更多内容

Saving stdout from subprocess.Popen to file, plus writing more stuff to the file

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

1
2
3
4
5
6
7
8
9
10
11
12
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的stdout刷新到日志中?可能还有另一件事:可执行文件A开始,然后挂在B上,在B打印完内容并完成后,A然后打印更多内容并完成。

我在RHE Linux上使用Python 2.4。


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

1
2
3
4
5
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()调用移到那里。


据我了解,A程序等待B执行其操作,并且A仅在B退出后退出。

如果B可以在不运行A的情况下启动,则可以按相反的顺序启动进程:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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则使用行缓冲) 。


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

1
2
3
4
5
6
7
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


您需要等到过程完成后才能继续。我也将代码转换为使用上下文管理器,它更干净。

1
2
3
4
5
6
7
8
9
10
11
12
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"