提问者:小点点

使用子流程从python脚本实时输出。波本()


在四处搜索之后,我定义了一个函数来执行类似于终端中的命令:

import shlex
import subprocess
def execute_cmd(cmd):
    p = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE)

    for line in iter(p.stdout.readline, b''):  # b'' here for python3
        sys.stdout.write(line.decode(sys.stdout.encoding))

    error = p.stderr.read().decode()
    if error:
        raise Exception(error)

它工作正常(输出是实时的),当我

execute_cmd('ping -c 5 www.google.com')

但是,当我使用execute\u cmd运行python脚本时,输出将打印出来,直到过程完成。

execute_cmd('python test.py')
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time

print('hello')
time.sleep(2)
print('hello, again')

我怎样才能修好它?谢谢

很抱歉没有解释为什么“捕获标准输出,然后再将其写入标准输出”。这里我真正想做的是捕捉脚本输出到记录器,记录器将它们输出到屏幕(StreamHandler)和日志文件(FileHandler)。我构建并测试了日志部分,现在是“执行”部分。忽略stdout=参数似乎不起作用。

  1. 设置日志;
  2. 重定向STDOUT,STDERR到记录器;
  3. 执行脚本;

由于步骤2的原因,如果忽略stdout=参数,脚本的输出仍然会输出到stdout,并且不会登录文件。

也许我可以将stdout=设置为logger?


共1个答案

匿名用户

这是底层输出系统的常见问题,尤其是在Linux或其他类似Unix的系统上。io库足够智能,可以在检测到输出被定向到终端时刷新每个\n上的输出。但当输出重定向到文件或管道时,可能出于性能原因,不会发生这种自动刷新。当只有数据重要时,这并不是一个真正的问题,但当时间也重要时,它会导致奇怪的行为。

不幸的是,我知道没有简单的方法来修复它从调用程序(*)。唯一的可能性是在每一行/块上使用被调用者强制刷新,或者使用无缓冲输出:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import time
import sys

print('hello')
sys.stdout.flush()
time.sleep(2)
print('hello, again')

(*)防弹方法是使用伪终端。调用方控制主端,并将客户端传递给被调用方。库将检测到一个终端,并将自动刷新每一行。但是它在Unix世界之外不再是可移植的,也不是一种真正简单的方式。