【问题标题】:Start scripts in POpen subprocesses and get their output continously在 POpen 子进程中启动脚本并连续获取它们的输出
【发布时间】:2019-12-19 13:40:21
【问题描述】:

嗨,我花了几天时间在 stackoverflow 上阅读答案,为什么我得到下面列出的输出,而不是永远看到 hello.py 中的循环计数。对我来说仍然不清楚,没有任何效果。如何在 POpen 子进程中启动一些脚本并连续获取它们的输出。不是在它们完成后,因为它们将永远运行。如果这被认为已经得到解答,如果有人可以链接到 Python3 的功能,我会很高兴。

我运行这个 .py 代码是希望看到 hello.py 执行:

import subprocess
import sys

command = [sys.executable, 'hello.py']
process_handle = subprocess.Popen(command, shell=True, stdout=subprocess.PIPE)

while process_handle.poll() is None:
    for line in iter(process_handle.stdout.readline, ""):
        output = line.decode('utf-8')
        if output != '':
            print('Last number is: ' + output)

这是我得到的。没有运行 hello.py:

Linux 上的 Python 3.7.3(默认,2019 年 4 月 3 日,05:39:12)[GCC 8.3.0] 输入“help”、“copyright”、“credits”或“license”了解更多信息。

hello.py 包含:

i = 0
while True:
    print(i)
    i=i+1
    sleep(1)

我尝试了来自live output from subprocess command 的第二个重复建议的第一个变体

它不编译/执行:

import subprocess
import sys
with open('test.log', 'w') as f:  # replace 'w' with 'wb' for Python 3
    process = subprocess.Popen(your_command, stdout=subprocess.PIPE)
    for c in iter(lambda: process.stdout.read(1), ''):  # replace '' with b'' for Python 3
        sys.stdout.write(c)
        f.write(c)

结果:

Traceback(最近一次调用最后一次):文件“hello.py”,第 11 行,在 Traceback(最近一次调用最后一次):文件“hello5.py”,行 7、在 sys.stdout.flush() NameError: name 'sys' is not defined sys.stdout.write(c) TypeError: write() argument must be str, not bytes

现在我尝试了上面的第二个变体,修改如下:

import subprocess
import sys

command = [sys.executable, 'hello.py']

process = subprocess.Popen(command, stdout=subprocess.PIPE)
for line in iter(process.stdout.readline, b''):  # replace '' with b'' for Python 3
    sys.stdout.write(line)

结果:

Traceback(最近一次调用最后一次):文件“hello.py”,第 11 行,在 Traceback(最近一次调用最后一次):文件“hello5.py”,行 8、在 sys.stdout.flush() NameError: name 'sys' is not defined sys.stdout.write(line) TypeError: write() argument must be str, not bytes

根据 ShadowRanger 的建议,我为二进制添加了 b'',但是 sys 已经导入:

import subprocess
import sys

command = [sys.executable, 'hello.py']

process = subprocess.Popen(command, stdout=subprocess.PIPE)
for c in iter(lambda: process.stdout.read(1), b''):  # replace '' with b'' for Python 3
sys.stdout.write(c)

结果,尽管添加了import sys,sys没有定义?另外现在它抱怨二进制并想要字符串。

Traceback(最近一次调用最后一次):文件“hello.py”,第 11 行,在 sys.stdout.flush() NameError: name 'sys' is not defined 回溯(最近一次调用最后):文件“hello5.py”,第 8 行,在 sys.stdout.write(c) TypeError: write() argument must be str, not bytes

好的,我使用 ShadowRanger 的信息并将二进制输出再次转换为文本。 hello.py 现在正在打印文本。

sys.stdout.write(c.decode('ASCII'))

但它一下子就来了,这不是我需要的。 hello.py 中的每一行打印都必须实时显示,而不仅仅是脚本完成时。

【问题讨论】:

  • @Chris 感谢您的建议。该线程中接受的答案是将 sys.stdout.flush() 添加到打印中。我将它添加到我所有的 print() 中,但不幸的是仍然没有结果。
  • 仅供参考,所有双参数 iter 调用的第二个参数都是错误的;你传递了"",空的str,但是你的Popen调用都是默认的二进制模式,所以你应该使用b""。您的最终回溯只是因为您在 hello5.py 脚本中使用了 sys.stdout 而没有使用 import sys,和/或您没有使用 sys.stdout.buffer.write(c)(因为再次,您有 bytes,并且您试图写信给基于文本的sys.stdout)。
  • @Rimfire:它在您的一个脚本的导入中,但不是由Popen 运行的那个。 write 的错误是因为 read/readline 仍然返回 bytes。你需要先了解bytesstr 在 Python 3 中是如何工作的;如果您不理解这一点,而只是使用subprocess 复制和粘贴为 Python 2 编写的代码,那么您将在错误之上遇到错误。有多种可能的修复方法,但如果您没有了解问题的背景知识,我不会通过零碎地指出问题来提供帮助。

标签: python python-3.x


【解决方案1】:

搞定了,感谢大家的帮助。为了实时获得输出而不是在脚本结束时获得全部输出,必须在子进程脚本(在这种情况下为 hello.py)中完成标准输出的刷新此外,就像 ShadowRanger 所说,如果使用二进制的 b''会有来自 stdout.write 的投诉。这可以通过解码为文本来处理。

你好.py

import sys
from time import sleep

i = 0
while True:
    print(i)
    sys.stdout.flush()
    i=i+1
    sleep(0.1)

mainscript.py

import sys
import subprocess
command = [sys.executable, 'hello.py']
process = subprocess.Popen(command, stdout=subprocess.PIPE)
for c in iter(lambda: process.stdout.read(1), b''):  # replace '' with b'' for Python 3
    sys.stdout.write(c.decode('utf-8'))  # decode b'' back to text

【讨论】:

    猜你喜欢
    • 2020-02-02
    • 1970-01-01
    • 2020-10-13
    • 2015-01-21
    • 2018-10-23
    • 1970-01-01
    • 2011-07-26
    • 1970-01-01
    相关资源
    最近更新 更多