将stdout从subprocess.Popen一行一行地保存到文件中

时间:2011-03-02 17:45:21

标签: python subprocess

我的python脚本使用子进程来调用另一个脚本,这会产生非常慢的输出(逐行)。我希望在整个过程结束时将输出逐行写入文件并将整个输出写为字符串。以下代码在“脚本”结束时将输出写入“文件”。

args = ("script")
file = open('output.txt', 'w')
subprocess.Popen(args,stdout=file)

甚至可能吗? Thanx,Chris

4 个答案:

答案 0 :(得分:2)

您可以使用轮询与流程进行交互,以便您可以尝试逐行进行交互:

例如:

process = subprocess.Popen(["ls", "-lart"],
                 bufsize=-1, # fully buffered (default)
                 stdin=subprocess.PIPE,
                 stdout=subprocess.PIPE,
                 stderr=subprocess.PIPE,
                 cwd=os.curdir,
                 env=os.environ)
my_stdout_file = open("stdout.txt", "w")
while True:
    process.poll()
    line = process.stdout.readline()
    my_stdout_file.write(line)
    eline = process.stderr.readline()
    if line:
        stdout_lines.append(line)
    if eline:
        stderr_lines.append(eline)
    if (line == "" and eline == "" and
        process.returncode != None):
        break

答案 1 :(得分:1)

是的,有可能。这是我为测试工具编写的一个函数,用于对Python shell脚本进行单元测试。

def testrun(cmdline):
   try:
      cmdout, cmderr = "",""
      cmdp = Popen(cmdline, shell=True,stdout=PIPE, stderr=PIPE)
      cmdout,cmderr =  cmdp.communicate()
      retcode = cmdp.wait()
      if retcode < 0:
         print >>sys.stderr, "Child was terminated by signal", -retcode
      else:
         return (retcode,cmdout,cmderr)
   except OSError, e:
      return (e,cmdout,cmderr)

该函数返回一个元组,其中包含sys.exit()发出的shell返回码,标准输出文本和标准错误输出文本。它们都是文本字符串,因此您需要在处理之前使用splitlines将它们分成行。

如果您确实需要逐行与输出进行交互,那么最好使用pexpect而不是subprocess模块。

答案 2 :(得分:1)

以为我会共享一个不使用.poll(),. wait()或.communicate()的解决方案。几点:

  • 我使用import codecs,因为我的输出包括东亚UTF-8文字
  • 我使用try:捕获每一行以过滤掉损坏/无效的UTF-8文本
  • 无论使用何种平台,我都使用'\x0a'来强制使用Linux换行符。
  • 如果您需要捕获stderr
  • ,请使用for line in iter(subproc.stderr.readline, ''):
  • 此方法仅在子程序创建输出时生成输出
  • 使用kw字典对于此示例来说是过度的,但是展示了如何将** kwargs与子进程一起使用

代码:

import subprocess
import codecs
import os

kw = {
    'bufsize': 0,
    'executable': None,
    'stdin': subprocess.PIPE,
    'stdout': subprocess.PIPE,
    'stderr': subprocess.PIPE,
    'preexec_fn': None,
    'close_fds': False,
    'shell': False,
    'cwd': None,
    'env': None,
    'universal_newlines': False,
    'startupinfo': None,
    'creationflags': 0,
    }

args = ['ls', '-lart']
kw['cwd'] = os.path.expanduser('~')
logfile = os.path.expanduser('~/stdout.txt')
stdlog = []

try:
    subproc = subprocess.Popen(args,**kw)
except:
    print 'Error loading subprocess. Check arguments and kwargs'
    exit()

log = codecs.open(logfile,'w','utf-8')
log.write(': Starting log for: \"%s\"\x0a'%(' '.join(args)))
for line in iter(subproc.stdout.readline, ''):
    try:
        stdlog.append(line.rstrip().decode('utf-8'))
        log.write(stdout[-1]+'\x0a')
        print stdout[-1]
    except:
        pass

log.flush()
log.close()

答案 3 :(得分:0)

对于我正在处理的编程语言,我遇到了同样的问题,最后这样做了:https://github.com/perimosocordiae/plumbum/blob/master/lib/stdlib.py#L21

不幸的是,它涉及一次从输出流中读取一个字符,累积该行直到找到换行符。但是它很有用,而且我不知道有任何其他方法可以获得相同的行为。