【问题标题】:Real-time intercepting of stdout from another process in Python在 Python 中实时截取另一个进程的标准输出
【发布时间】:2010-11-08 06:37:50
【问题描述】:

我想运行一个系统进程,截取输出,并在 Python 脚本中逐行实时修改。

我的最佳尝试是:在打印之前等待该过程完成:

#!/usr/bin/env python
import subprocess

cmd = "waitsome.py"
proc = subprocess.Popen(cmd, shell=True, bufsize=256, stdout=subprocess.PIPE)
for line in proc.stdout:
    print ">>> " + line.rstrip()

脚本waitsome.py 只是每半秒打印一行:

#!/usr/bin/env python
import time
from sys import stdout

print "Starting"
for i in range(0,20):
    time.sleep(0.5)
    print "Hello, iteration", i
    stdout.flush()

是否有一个简单的解决方案可以让subprocess 允许实时迭代输出?我必须使用线程吗?

曾几何时,我用 Perl 编写脚本,这简直是小菜一碟:

open(CMD, "waitsome.py |");
while (<CMD>) {
    print ">>> $_";
}
close(CMD);

【问题讨论】:

标签: python perl process


【解决方案1】:

循环遍历文件不可避免地会以相当大的块缓冲内容——这是所有 Python 2.* 实现的一个已知问题。它在 Python 3.1 中按您的预期工作,最终循环略有不同:

for line in proc.stdout:
    print(">>> " + str(line.rstrip()))

如果升级到 Python 3.1 是不切实际的(我知道它经常会这样!),换一种方式,以老式的方式编写循环 - 以下版本的循环确实可以在 Python 中按您的意图工作2.*:

while True:
    line = proc.stdout.readline()
    if not line:
        break
    print ">>> " + line.rstrip()

【讨论】:

  • 是的,但是现在 Python 3.1 已经发布(整个 I/O 堆栈的实现要好得多),没有理由坚持使用 3.0(它绝对是一个过渡版本;-)。
  • for line in iter(proc.stdout.readline, ''): print "&gt;&gt;&gt;", line, 可以用来代替 Python 2 上的 while 循环。
【解决方案2】:

这整件事可以封装在一个迭代器中:

def subprocess_readlines(out):
    while True:
        line = out.readline()
        if not line:
            return
        yield line

并称为:

for line in subprocess_readlines(proc.stdout):
    print ">>>", line.rstrip()

【讨论】:

  • 自从我写了最初的问题以来,Python 中的缓冲已经发生了很大的变化 :) 是的,python 2.5 付出了很多努力现在可以在几行中完成。
  • 我不明白这种方法需要在哪里定义 subprocess_readlines。你能详细说明一下吗?
  • 哎呀。我没有将电话添加到subprocess_readlines()。我刚刚更新了。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-01
  • 2011-03-25
  • 2023-04-06
  • 2011-09-18
  • 1970-01-01
  • 2013-06-25
  • 2010-10-06
相关资源
最近更新 更多