逐行读取subprocessstdout

我的Python脚本使用subprocess调用非常嘈杂的Linux实用程序。 我想将所有的输出存储到一个日志文件,并显示给用户。 我认为以下方法可行,但是在应用程序产生大量输出之前,输出不会显示在我的应用程序中。

#fake_utility.py, just generates lots of output over time import time i = 0 while True: print hex(i)*512 i += 1 time.sleep(0.5) #filters output import subprocess proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE) for line in proc.stdout: #the real code does filtering here print "test:", line.rstrip() 

我真正想要的行为是filter脚本打印从subprocess收到的每一行。 Sorta像什么tee ,但与Python代码。

我错过了什么? 这甚至有可能吗?


更新:

如果将一个sys.stdout.flush()添加到fake_utility.py中,则代码在python 3.1中具有所需的行为。 我使用Python 2.6。 你会认为使用proc.stdout.xreadlines()会像py3k一样工作,但是不会。


更新2:

这是最小的工作代码。

 #fake_utility.py, just generates lots of output over time import sys, time for i in range(10): print i sys.stdout.flush() time.sleep(0.5) #display out put line by line import subprocess proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE) #works in python 3.0+ #for line in proc.stdout: for line in iter(proc.stdout.readline,''): print line.rstrip() 

自从我上次使用Python之后已经很长时间了,但是我认为问题在于for line in proc.stdout声明,它在遍历它之前读取整个input。 解决方法是使用readline()来代替:

 #filters output import subprocess proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE) while True: line = proc.stdout.readline() if line != '': #the real code does filtering here print "test:", line.rstrip() else: break 

当然你还是要处理subprocess的缓冲。

注意: 根据文档 ,带有迭代器的解决scheme应该等同于使用readline() ,除了预读缓冲区,但是(或者正是因为如此)build议的更改对我来说产生了不同的结果(Windows上的Python 2.5 XP)。

事实上,如果你整理了迭代器,那么缓冲现在可能成为你的问题。 你可以告诉subprocess中的python不要缓冲它的输出。

 proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE) 

 proc = subprocess.Popen(['python','-u', 'fake_utility.py'],stdout=subprocess.PIPE) 

从python中调用python时,我需要这个。

晚会晚了,但很惊讶,看不到我认为是最简单的解决scheme:

 import io import subprocess proc = subprocess.Popen(["prog", "arg"], stdout=subprocess.PIPE) for line in io.TextIOWrapper(proc.stdout, encoding="utf-8"): # or another encoding # do something with line 

你想把这些额外的parameter passing给subprocess.Popen

 bufsize=1, universal_newlines=True 

然后你可以迭代你的例子。 (用Python 3.5testing)

Python 2和3(2.7.12和3.6.1)对Rômulo的答案进行了如下修改:

 import os import subprocess process = subprocess.Popen(command, stdout=subprocess.PIPE) while True: line = process.stdout.readline() if line != b'': os.write(1, line) else: break 

所有你需要做的就是运行subprocess.call():util.py:

 #!的/ usr / bin中/ python2.6的

导入subprocess

 command = ['./fake_util.py']

尝试:
   proc = subprocess.call(命令)
除了OSError,err:
  打印'有执行命令运行命令“%s”:%s'%(command,err)

fake_util.py:

 #!的/ usr / bin中/ python2.6的
 #fake_utility.py,只是随着时间的推移产生大量的输出
import时间
我= 0
而真:
   打印hex(i)* 512
   我+ = 1
    time.sleep(0.5)

运行./util.py现在会在生成时生成输出:

 x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x10x1

 ./util.py

 ^ CTraceback(最近的通话最后):
  文件“./util.py”,第8行, 
     proc = subprocess.call(命令)
  在调用中,文件“/usr/lib/python2.6/subprocess.py”,第480行
    返回Popen(* popenargs,** kwargs).wait()
  文件“/usr/lib/python2.6/subprocess.py”,行1170,等待
回溯(最近一次通话最后):
  文件“./fake_util.py”,第8行, 
     time.sleep(0.5)
一个KeyboardInterrupt
     pid,sts = _eintr_retry_call(os.waitpid,self.pid,0)
  在_eintr_retry_call中的文件“/usr/lib/python2.6/subprocess.py”,第465行
    返回func(* args)
一个KeyboardInterrupt