繁体   English   中英

如何在 Python 中使用子进程获取实时输出

[英]How to get live output with subprocess in Python

我正在尝试运行一个打印某些东西的 python 文件,等待 2 秒,然后再次打印。 我想从我的 python 脚本中实时捕获这些输出,然后处理它们。 我尝试了不同的东西,但没有任何效果。

process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
while True:
    output = process.stdout.readline()
    if process.poll() is not None and output == '':
        break
    if output:
        print(output.strip())

我在这一点上,但它不起作用。 它一直等到代码完成,然后打印所有输出。

我只需要运行一个 python 文件并从中获取实时输出,如果您有其他想法,不使用打印功能,请告诉我,只知道我必须单独运行该文件。 我只是想到了最简单的方法,但是,据我所见,它无法完成。

这里有三层缓冲,你需要限制这三层以保证你得到实时数据:

  1. 使用stdbuf命令(在 Linux 上)包装subprocess进程的执行(例如运行['stdbuf', '-oL'] + cmd而不仅仅是cmd ),或者(如果你有能力这样做)将程序本身更改为要么显式更改stdout上的缓冲(例如,使用 C/C++ 代码的setvbufstdout全局切换到行缓冲模式,而不是输出到非 tty 时使用的默认块缓冲)或在关键输出后插入刷新语句(例如fflush(stdout);用于 C/C++, fileobj.flush()用于 Python 等)程序的缓冲到面向行的模式(或添加 fflushs); 否则,一切都会卡在子进程的用户模式缓冲区中。

  2. bufsize=0添加到Popen参数(可能不需要,因为您不向标准输入发送任何内容,但无害),因此它会取消缓冲所有管道句柄。 如果Popen处于text=True模式,则切换到bufsize=1 (这是行缓冲的,而不是无缓冲的)。

  3. flush=True添加到print参数(如果您连接到终端,则行缓冲将为您刷新它,因此只有将 stdout 通过管道传输到文件时才有意义),或显式调用sys.stdout.flush()

在这三者之间,您应该能够保证没有数据卡在用户模式缓冲区中等待; 如果子流程至少已经输出了一行,它会立即到达您的手中,并且由它触发的任何输出也将立即出现。 在大多数情况下,第 1 项是最难的(当您无法使用stdbuf ,或者进程在内部重新配置自己的缓冲并撤消stdbuf的效果,并且您无法修改进程可执行文件来修复它); 您可以完全控制 #2 和 #3,但 #1 可能不在您的控制范围内。

这是我用于相同目的的代码:

def run_command(command, **kwargs):
    """Run a command while printing the live output"""
    process = subprocess.Popen(
        command,
        stdout=subprocess.PIPE,
        stderr=subprocess.STDOUT,
        **kwargs,
    )
    while True:   # Could be more pythonic with := in Python3.8+
        line = process.stdout.readline()
        if not line and process.poll() is not None:
            break
        print(line.decode(), end='')

一个使用示例是:

run_command(['git', 'status'], cwd=Path(__file__).parent.absolute())

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM