如果我使用例如“ls -Rlah /”运行以下函数“run”,我会立即通过print语句获得输出
import subprocess32 as subprocess
def run(command):
process = subprocess.Popen(command,
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
try:
while process.poll() == None:
print process.stdout.readline()
finally:
# Handle the scenario if the parent
# process has terminated before this subprocess
if process.poll():
process.kill()
但是,如果我使用下面的python示例程序,它似乎会停留在process.poll()或process.stdout.readline()上,直到程序完成。我认为它是stdout.readline(),因为如果我将输出的字符串数量从10增加到10000(在示例程序中)或者在每次打印后添加到sys.stdout.flush()中,则在运行中打印函数确实被执行了。
如何使子流程的输出更加实时?
注意:我刚刚发现python示例程序在输出时没有执行sys.stdout.flush(),是否有办法让子进程的调用者以某种方式强制执行此操作?
每5秒输出10个字符串的示例程序。
#!/bin/env python
import time
if __name__ == "__main__":
i = 0
start = time.time()
while True:
if time.time() - start >= 5:
for _ in range(10):
print "hello world" + str(i)
start = time.time()
i += 1
if i >= 3:
break
答案 0 :(得分:3)
在大多数系统上,命令行程序行缓冲区或块缓冲区取决于stdout
是终端还是管道。在unixy系统上,父进程可以创建一个伪终端,以获得类似终端的行为,即使孩子并非真正从终端运行。您可以使用pty
模块创建伪终端或使用pexpect
模块,以便轻松访问交互式程序。
如评论中所述,使用poll
读取行可能会导致数据丢失。一个例子是当进程终止时在stdout管道中留下的数据。阅读pty
与管道有点不同,当您关闭子项以使其全部正常工作时,您会发现需要捕获IOError,如下例所示。
try:
import subprocess32 as subprocess
except ImportError:
import subprocess
import pty
import sys
import os
import time
import errno
print("running %s" % sys.argv[1])
m,s = (os.fdopen(pipe) for pipe in pty.openpty())
process = subprocess.Popen([sys.argv[1]],
stdin=s,
stdout=s,
stderr=subprocess.STDOUT)
s.close()
try:
graceful = False
while True:
line = m.readline()
print line.rstrip()
except IOError, e:
if e.errno != errno.EIO:
raise
graceful = True
finally:
# Handle the scenario if the parent
# process has terminated before this subprocess
m.close()
if not graceful:
process.kill()
process.wait()
答案 1 :(得分:2)
您应该在脚本中刷新标准输出:
print "hello world" + str(i)
sys.stdout.flush()
当标准输出是终端时,stdout是行缓冲的。但是当它不是时,stdout是块缓冲的,你需要明确地刷新它。
如果您无法更改脚本源,可以使用Python的-u
选项(在子流程中):
-u Force stdin, stdout and stderr to be totally unbuffered.
您的命令应该是:['python', '-u', 'script.py']
通常,这种缓冲发生在用户空间中。没有通用的方法来强制应用程序刷新其缓冲区:某些应用程序支持命令行选项(如Python),其他应用程序支持信号,其他应用程序不支持任何内容。
一种解决方案可能是模拟伪终端,提供"提示"他们应该在行缓冲模式下运行的程序。尽管如此,这并不是一个适用于所有情况的解决方案。
答案 2 :(得分:2)
对于python之外的其他内容,您可以尝试使用unbuffer:
unbuffer禁用从非交互式程序重定向程序输出时发生的输出缓冲。例如,假设您通过运行od然后更多来查看fifo的输出。 od -c / tmp / fifo |更多 在生成整页输出之前,您将看不到任何内容。 您可以按如下方式禁用此自动缓冲:
unbuffer od -c /tmp/fifo | more
通常,unbuffer不会从stdin读取。这在某些情况下简化了unbuffer的使用。要在管道中使用unbuffer,请使用-p标志。例: process1 | unbuffer -p process2 | process3
所以在你的情况下:
run(["unbuffer",cmd])
文档中列出了一些警告,但这是另一种选择。