Python 逐行读取子进程标准

Python 逐行读取子进程标准,python,subprocess,Python,Subprocess,我的python脚本使用子进程调用一个非常嘈杂的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) #filte

我的python脚本使用子进程调用一个非常嘈杂的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()
我真正想要的行为是过滤器脚本在从子流程接收到每一行时打印它。有点像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已经有很长一段时间了,但我认为问题在于proc.stdout中line的语句
,它在迭代之前读取整个输入。解决方案是使用
readline()

#filters output
import subprocess
proc = subprocess.Popen(['python','fake_utility.py'],stdout=subprocess.PIPE)
while True:
  line = proc.stdout.readline()
  if not line:
    break
  #the real code does filtering here
  print "test:", line.rstrip()
当然,您仍然需要处理子流程的“缓冲”


注意:使用迭代器的解决方案应该相当于使用
readline()
,但预读缓冲区除外,但是(或者正因为如此)建议的更改确实为我产生了不同的结果(Windows XP上的Python 2.5)。

事实上,如果您整理了迭代器,那么缓冲现在可能是您的问题。您可以告诉子进程中的python不要缓冲其输出

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

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

从python内部调用python时,我需要这个参数。

您想将这些额外参数传递给
subprocess.Popen

bufsize=1, universal_newlines=True

然后可以像示例中那样进行迭代。(使用Python 3.5进行测试)

派对迟到了一点,但很惊讶没有看到我认为最简单的解决方案:

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

(这需要Python 3。)

以下对Rômulo答案的修改适用于Python 2和3(2.7.12和3.6.1):

导入操作系统
导入子流程
process=subprocess.Popen(命令,stdout=subprocess.PIPE)
尽管如此:
line=process.stdout.readline()
如果行!='':
操作系统写入(1,行)
其他:
打破

我用python3试过了,效果很好


您还可以读取不带循环的行。在python3.6中工作

import os
import subprocess

process = subprocess.Popen(command, stdout=subprocess.PIPE)
list_of_byte_strings = process.stdout.readlines()

一种函数,允许同时逐行实时迭代
stdout
stderr

如果需要同时获取
stdout
stderr
的输出流,可以使用以下函数

该函数使用队列将两个Popen管道合并到一个迭代器中

这里我们创建函数
read\u popen\u pipes()

从队列导入队列,空
从concurrent.futures导入ThreadPoolExecutor
def排队_输出(文件、队列):
对于iter中的行(file.readline“”):
队列.放置(行)
file.close()文件
def读取管道(p):
使用ThreadPoolExecutor(2)作为池:
q_stdout,q_stderr=Queue(),Queue()
pool.submit(排队输出、p.stdout、q\u stdout)
pool.submit(排队输出、p.stderr、q\u stderr)
尽管如此:
如果p.poll()不是None且q_stdout.empty()和q_stderr.empty():
打破
输出线=错误线=“”
尝试:
out\u line=q\u stdout.get\u nowait()
除空外:
通过
尝试:
err_line=q_stderr.get_nowait()
除空外:
通过
收益率(外线、错误线)
read\u popen\u pipes()
正在使用:

将子流程作为sp导入
将sp.Popen(my_cmd,stdout=sp.PIPE,stderr=sp.PIPE,text=True)作为p:
对于输出管线,读取管线中的错误管线(p):
#对每一行都做些事情,例如:
打印(输出行,结束=“”)
打印(错误行,结束=“”)
返回p.poll()#返回状态代码

pythont3.5将方法
run()
call()
添加到
子流程
模块,两者都返回一个
CompletedProcess
对象。这样,您就可以使用
proc.stdout.splitlines()


另请参见

您可以使用
print line,
而不是
print line.rstrip()
(注意:结尾是逗号)。相关:更新2声明它与python 3.0+一起工作,但使用了旧的print语句,因此它与python 3.0+不工作。这里列出的答案对我来说都不起作用,但确实起作用!有趣的是,仅适用于python3.0+的代码使用2.7语法打印。对于
file.readline()
vs.
对于文件中的行
请参见(简而言之:它适用于python3;对于Python2.6+使用
io.open()
)根据PEP 8()中的“编程建议”,对EOF进行更具Python风格的测试,将是“如果不是线:”。@naxa:for pipes:
for iter中的线(proc.stdout.readline),:
@Jan PhilipGehrcke:yes。1.您可以在Python3(不存在预读错误)2上为proc.stdout中的行使用
<代码>'''=b'
在Python3上--不要盲目复制粘贴代码--思考它的功能和工作方式。在中断之前,我建议添加
sys.stdout.flush()
,否则事情会搞砸。我想用这个答案,但我得到了:
AttributeError:“file”对象没有属性“readable”
py2.7与python一起工作3@sorin这两件事都不能使它“无效”。如果您正在编写一个仍然需要支持Python2的库,那么不要使用此代码。但许多人都有幸能够使用十多年前发布的软件。如果你试图读取一个关闭的文件,不管你是否使用
TextIOWrapper
,你都会得到这个异常。你可以简单地处理这个异常。你可能迟到了
import os
import subprocess

process = subprocess.Popen(command, stdout=subprocess.PIPE)
list_of_byte_strings = process.stdout.readlines()
proc = subprocess.run( comman, shell=True, capture_output=True, text=True, check=True )
for line in proc.stdout.splitlines():
   print "stdout:", line