实时subprocess.Popen通过stdout和PIPE

alf*_*eza 18 python logging subprocess pipe popen

我试图stdout通过subprocess.Popen电话抓住,虽然我通过这样做很容易实现:

cmd = subprocess.Popen('ls -l', shell=True, stdout=PIPE)
for line in cmd.stdout.readlines():
    print line
Run Code Online (Sandbox Code Playgroud)

我想stdout"实时" 抓住.使用上面的方法,PIPE正在等待抓取所有stdout,然后它返回.

因此,对于记录目的,这不符合我的要求(例如,"看到"发生时发生的事情).

有没有办法一行一行地stdout运行?或者这是一个限制subprocess(必须等到PIPE关闭).

编辑 如果我转readlines()readline(),我只得到了最后一行stdout(不理想):

In [75]: cmd = Popen('ls -l', shell=True, stdout=PIPE)
In [76]: for i in cmd.stdout.readline(): print i
....: 
t
o
t
a
l

1
0
4
Run Code Online (Sandbox Code Playgroud)

小智 19

你的口译员正在缓冲.在print语句后添加对sys.stdout.flush()的调用.

  • @alfredodeza:它不可能工作 `.readlines()` 不会返回,直到 *所有输出* 被读取(直到 EOF 发生),因此添加 `sys.stdout.flush()` 不会改变任何东西。它与您的要求相矛盾:*“有没有办法在 [子进程] 运行时逐行获取标准输出?”* (2认同)

Und*_*ndo 13

实际上,真正的解决方案是直接将子进程的stdout重定向到进程的stdout.

实际上,使用您的解决方案,您只能同时打印stdout而不是stderr.

import sys
from subprocess import Popen
Popen("./slow_cmd_output.sh", stdout=sys.stdout, stderr=sys.stderr).communicate()
Run Code Online (Sandbox Code Playgroud)

communicate()如此使呼叫阻塞,直到子进程结束,否则它会直接进入下一行,你的程序可能在子进程之前终止(虽然重定向到你的标准输出仍然可以工作,你的Python脚本关闭后,我测试了它).

这样,例如,您将以绝对实时方式重定向stdout和stderr.

例如,在我的情况下,我使用此脚本进行了测试slow_cmd_output.sh:

#!/bin/bash

for i in 1 2 3 4 5 6; do sleep 5 && echo "${i}th output" && echo "err output num ${i}" >&2; done
Run Code Online (Sandbox Code Playgroud)

  • 注意:我知道该线程很旧,但是我遇到了这个线程,答案让我不满意。找到答案后,我想我也应该把它贴出来:) (2认同)

Ale*_*lli 11

要"实时"输出,subprocess是不合适的,因为它无法击败其他进程的缓冲策略.这就是我总是推荐的原因,每当需要这样的"实时"输出抓取时(在堆栈溢出时非常频繁的问题!),而是使用pexpect(除了Windows 之外的所有地方 - 在Windows上,wexpect).