【问题标题】:Python: How to read stdout of subprocess in a nonblocking wayPython:如何以非阻塞方式读取子进程的标准输出
【发布时间】:2016-07-28 08:58:17
【问题描述】:

我正在尝试制作一个简单的 python 脚本来启动一个子进程并监视其标准输出。这是代码中的一个sn-p:

process = subprocess.Popen([path_to_exe, os.path.join(temp_dir,temp_file)], stdout=subprocess.PIPE)
while True:   
    output=process.stdout.readline()
    print "test"

问题在于脚本在output=process.stdout.readline() 上挂起,并且print "test" 行仅在子进程终止后执行。

有没有办法读取标准输出并打印它而不必等待子进程终止?

我要启动的子进程是一个 Windows 二进制文件,我没有它的源代码。

我发现了几个类似的问题,但答案仅适用于 Linux 或我有我要启动的 suprocess 的来源。

【问题讨论】:

  • 我认为您需要提供有关可执行文件的更多详细信息。二进制文件的样本输出是什么?单行还是多行?听起来二进制文件不太适合这样的接口。因为只有在二进制终止时才会刷新输出。
  • 我实际上想模糊不同的二进制文件(Acrobat 阅读器以及其他)并检测崩溃。我可以得到退出代码,但我也想要标准输出/错误。

标签: python subprocess output standards


【解决方案1】:

检查select模块

import subprocess
import select
import time
    
x=subprocess.Popen(['/bin/bash','-c',"while true; do sleep 5; echo yes; done"],stdout=subprocess.PIPE)
    
y=select.poll()
y.register(x.stdout,select.POLLIN)

while True:
  if y.poll(1):
     print x.stdout.readline()
  else:
     print "nothing here"
     time.sleep(1)

编辑:

非 posix 系统的线程解决方案:

import subprocess
from threading import Thread 
import time
 
linebuffer=[]
x=subprocess.Popen(['/bin/bash','-c',"while true; do sleep 5; echo yes; done"],stdout=subprocess.PIPE)

def reader(f,buffer):
   while True:
     line=f.readline()
     if line:
        buffer.append(line)
     else:
        break

t=Thread(target=reader,args=(x.stdout,linebuffer))
t.daemon=True
t.start()

while True:
  if linebuffer:
     print linebuffer.pop(0)
  else:
     print "nothing here"
     time.sleep(1)

【讨论】:

  • 我收到消息“AttributeError: 'module' object has no attribute 'poll'。会不会是该模块与 Windows 不同?
  • 似乎 select 无法在 Windows 上处理流,建议使用 here 线程作为下一个最佳选项。
  • 如果您在一次投票中获得多行,似乎您将反向打印输出行。使用 pop(0) 而不是 pop() 会解决它
  • 令我惊讶的是,当我删除print linebuffer.pop(0)时,程序仍然打印子进程输出,输出是从哪里来的?
  • 可能是打印到stderr?
【解决方案2】:

你可以试试这个:

import subprocess
import os

""" Continuously print command output """
""" Will only work if there are newline characters in the output. """

def run_cmd(command):    
    popen = subprocess.Popen(command, stdout=subprocess.PIPE)
    return iter(popen.stdout.readline, b"")

for line in run_cmd([path_to_exe, os.path.join(temp_dir,temp_file)]):
    print(line), # the comma keeps python from adding an empty line

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-03-29
    • 1970-01-01
    • 2011-09-18
    • 2018-06-23
    • 2017-12-30
    • 2010-11-19
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多