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 的文本在屏幕上实际可见。