逐行读取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