lin将stdout从subprocess.Popen保存到文件行

2024-05-10 01:43:18 发布

您现在位置:Python中文网/ 问答频道 /正文

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

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

有可能吗?Thanx,克里斯


Tags: 文件字符串代码txt脚本output进程过程
3条回答

我想我可以共享一个不使用.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()

您可以使用poll与流程交互,以便尝试逐行与之交互:

例如:

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

是的,这是可能的。下面是我为一个测试工具编写的一个函数,用于对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模块。

相关问题 更多 >