从Windows上的subprocess.stdout实时读取



强调一下,问题是实时读取而不是非阻塞读取。以前有人问过,例如子过程。Popen.stdout - 实时(再次)读取标准输出。但是没有提出令人满意的解决办法。

例如,以下代码尝试模拟 python shell。

import subprocess
p = subprocess.Popen(['python'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
while True:
    line = input('>>> ')
    p.stdin.write(line.encode())
    print('>>> ', p.stdout.read().decode())

但是,从p.stdout读取时,它将被阻止。四处搜索后,我找到了以下两种可能的souts。

  1. 使用fctrlO_NONBLOCK
  2. 使用threadqueue

虽然第一个 soution 可能有效并且只适用于 linux,但第二个 soution 只是将阻塞读取转换为非阻塞读取,即我无法获得子进程的实时输出。例如,如果我输入" print("hello") ",则使用第二个解决方案p.stdout将一无所获。

也许,有人会建议p.communite.不幸的是,它不适合这种情况,因为它会关闭 stdin,如此处所述。

那么,有没有针对Windows的解决方案?

已编辑:即使打开-up.stdout.read替换为p.stdout.readline,问题仍然存在。

import subprocess
p = subprocess.Popen(['python', '-u'], stdin=subprocess.PIPE, stdout=subprocess.PIPE)
while True:
    line = input('>>> ')
    p.stdin.write(line.encode())
    p.stdin.flush()
    print('>>> ', p.stdout.readline().decode())

解决方案:以下是基于 J.F. Sebastian 的答案和注释的最终代码。

from subprocess import Popen, PIPE, STDOUT
with Popen(
        ['python', '-i', '-q'],
        stdin=PIPE, stdout=PIPE, stderr=STDOUT,
        bufsize=0
    ) as process:
    while True:
        line = input('>>> ')
        if not line:
            break
        process.stdin.write((line+'n').encode())
        print(process.stdout.readline().decode(), end='')

应该注意的是,当命令触发无输出时,程序将挂起。

下面是一个以交互方式使用子流程的完整工作示例:

#!/usr/bin/env python3
import sys
from subprocess import Popen, PIPE, DEVNULL
with Popen([sys.executable, '-i'], stdin=PIPE, stdout=PIPE, stderr=DEVNULL,
           universal_newlines=True) as process:
    for i in range(10):
        print("{}**2".format(i), file=process.stdin, flush=True)
        square = process.stdout.readline()
        print(square, end='')

下面是另一个示例:如何以交互方式运行[sys.executable, '-u', 'test.py']

相关内容

  • 没有找到相关文章

最新更新