Windows 从 subprocess.stdout 实时读取
Real time read from subprocess.stdout on Windows
强调一下,问题是实时读取而不是非阻塞读取。之前有人问过,例如subprocess.Popen.stdout - reading stdout in real-time (again)。但一直没有提出令人满意的解决方案。
例如,下面的代码试图模拟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
时会被阻塞。经过四处寻找,我发现了以下两种可能的解决方案。
- using
fctrl
and O_NONBLOCK
- using
thread
and queue
虽然第一个解决方案可能工作并且只在 linux 上工作,第二个解决方案只是将阻塞读取转换为非阻塞读取,即我无法获得子进程的实时输出。例如,如果我输入“print("hello")
”,使用第二种解决方案我将无法从 p.stdout
中得到任何结果。
也许有人会建议p.communite
。不幸的是,它不适合这种情况,因为它会按照 .
所述关闭标准输入
那么,Windows有什么解决办法吗?
编辑:即使开启-u
,将p.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的最终代码。塞巴斯蒂安的回答和评论。
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='')
这是另一个例子:。
强调一下,问题是实时读取而不是非阻塞读取。之前有人问过,例如subprocess.Popen.stdout - reading stdout in real-time (again)。但一直没有提出令人满意的解决方案。
例如,下面的代码试图模拟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
时会被阻塞。经过四处寻找,我发现了以下两种可能的解决方案。
- using
fctrl
andO_NONBLOCK
- using
thread
andqueue
虽然第一个解决方案可能工作并且只在 linux 上工作,第二个解决方案只是将阻塞读取转换为非阻塞读取,即我无法获得子进程的实时输出。例如,如果我输入“print("hello")
”,使用第二种解决方案我将无法从 p.stdout
中得到任何结果。
也许有人会建议p.communite
。不幸的是,它不适合这种情况,因为它会按照
那么,Windows有什么解决办法吗?
编辑:即使开启-u
,将p.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的最终代码。塞巴斯蒂安的回答和评论。
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='')
这是另一个例子: