Python 子进程标准输出不捕获输入提示
Python subprocess stdout doesn't capture input prompt
我正在使用子进程生成 conda create
命令并捕获生成的 stdout
供以后使用。我还立即将 stdout
打印到控制台,以便用户仍然可以看到子进程的进度:
p = subprocess.Popen('conda create -n env1 python', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in iter(p.stdout.readline, b''):
sys.stdout.write(line.decode(sys.stdout.encoding))
当 conda create
需要用户输入时,这在执行到一半之前工作正常:它提示 Proceed (n/y)?
并等待用户输入选项。但是,上面的代码不会打印提示,而只是等待“在空白屏幕上”输入。收到输入后,之后 将打印提示,然后按预期继续执行。
我认为这是因为输入以某种方式阻止了写入 stdout
的提示,因此 readline
直到输入块解除后才接收到新数据。
有没有办法确保在子进程等待用户输入之前打印输入提示?请注意,我在 Windows 上 运行。
对于这个用例,我建议使用 pexpect。 标准输入!=标准输出
根据 stdout
上的提示有条件地发送到 stdin 的示例用例
def expectgit(alog):
TMPLOG = "/tmp/pexpect.log"
cmd = f'''
ssh -T git@github.com ;\
echo "alldone" ;
'''
with open(TMPLOG, "w") as log:
ch = pexpect.spawn(f"/bin/bash -c \"{cmd}\"", encoding='utf-8', logfile=log)
while True:
i = ch.expect(["successfully authenticated", "Are you sure you want to continue connecting"])
if i == 0:
alog.info("Git all good")
break
elif i == 1:
alog.info("Fingerprint verification")
ch.send("yes\r")
ch.expect("alldone")
i = ch.expect([pexpect.EOF], timeout=5)
ch.close()
alog.info("expect done - EOF")
with open(TMPLOG) as log:
for l in log.readlines():
alog.debug(l.strip())
虽然我确信 pexpect 在这种情况下会奏效,但我认为这会有点矫枉过正。相反,我使用了 MisterMiyagi 的见解并将 readline
替换为 read
。
最终代码如下:
p = subprocess.Popen('conda create -n env1 python', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while p.poll() is None:
sys.stdout.write(p.stdout.read(1).decode(sys.stdout.encoding))
sys.stdout.flush()
请注意 read(1)
,因为仅使用 read()
会阻塞 while 循环,直到找到 EOF。如果在输入提示之前没有找到 EOF,则根本不会打印任何内容!此外,调用 flush
可确保写入 sys.stdout
的文本在屏幕上实际可见。
我正在使用子进程生成 conda create
命令并捕获生成的 stdout
供以后使用。我还立即将 stdout
打印到控制台,以便用户仍然可以看到子进程的进度:
p = subprocess.Popen('conda create -n env1 python', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
for line in iter(p.stdout.readline, b''):
sys.stdout.write(line.decode(sys.stdout.encoding))
当 conda create
需要用户输入时,这在执行到一半之前工作正常:它提示 Proceed (n/y)?
并等待用户输入选项。但是,上面的代码不会打印提示,而只是等待“在空白屏幕上”输入。收到输入后,之后 将打印提示,然后按预期继续执行。
我认为这是因为输入以某种方式阻止了写入 stdout
的提示,因此 readline
直到输入块解除后才接收到新数据。
有没有办法确保在子进程等待用户输入之前打印输入提示?请注意,我在 Windows 上 运行。
对于这个用例,我建议使用 pexpect。 标准输入!=标准输出
根据 stdout
上的提示有条件地发送到 stdin 的示例用例def expectgit(alog):
TMPLOG = "/tmp/pexpect.log"
cmd = f'''
ssh -T git@github.com ;\
echo "alldone" ;
'''
with open(TMPLOG, "w") as log:
ch = pexpect.spawn(f"/bin/bash -c \"{cmd}\"", encoding='utf-8', logfile=log)
while True:
i = ch.expect(["successfully authenticated", "Are you sure you want to continue connecting"])
if i == 0:
alog.info("Git all good")
break
elif i == 1:
alog.info("Fingerprint verification")
ch.send("yes\r")
ch.expect("alldone")
i = ch.expect([pexpect.EOF], timeout=5)
ch.close()
alog.info("expect done - EOF")
with open(TMPLOG) as log:
for l in log.readlines():
alog.debug(l.strip())
虽然我确信 pexpect 在这种情况下会奏效,但我认为这会有点矫枉过正。相反,我使用了 MisterMiyagi 的见解并将 readline
替换为 read
。
最终代码如下:
p = subprocess.Popen('conda create -n env1 python', stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
while p.poll() is None:
sys.stdout.write(p.stdout.read(1).decode(sys.stdout.encoding))
sys.stdout.flush()
请注意 read(1)
,因为仅使用 read()
会阻塞 while 循环,直到找到 EOF。如果在输入提示之前没有找到 EOF,则根本不会打印任何内容!此外,调用 flush
可确保写入 sys.stdout
的文本在屏幕上实际可见。