首页 > 解决方案 > 如何将输入流式传输到 python Popen 子进程并从中流式输出?

问题描述

我正在尝试使用subprocess.Popen. 作为用于测试目的的样板代码,这就是我所拥有的:

if __name__ == '__main__':
    ps = subprocess.Popen(
        input('command? '),
        shell=True,
        stdin=subprocess.PIPE,
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE,
        text=True
    )

    print(ps.stdout.read())
    time.sleep(1) # provide enough time to register completion if the command is a one-off, like dir or echo
    while ps.poll() == None: # ps.poll() returns None if still running
        try:
            # method one
            ps.stdin.write(input())
            ps.communicate()
            print(ps.stdout.read())

            # method two
            ps.stdin.write(input())
            print(ps.communicate()[0])

            # method three
            print(ps.communicate(input())[0])
        except:
            continue

    print('Process Finished')

每种方法都是不同的(失败的)尝试。

对于python应该打开 python CLI 解释器的命令,这完全失败了。但是,对于一次性命令,例如dir甚至ls运行python -c "<some python>"它就可以了。

命令行日志:

C:\Users\nj2u2\Desktop\test>python test.py
command? echo hello
hello

Process Finished

C:\Users\nj2u2\Desktop\test>python test.py
command? dir
 Volume in drive C has no label.
 Volume Serial Number is D6B7-6B8D

 Directory of C:\Users\nj2u2\Desktop\test

07/03/2020  12:26 AM    <DIR>          .
07/03/2020  12:26 AM    <DIR>          ..
07/03/2020  08:20 PM             6,811 subprocess_plus.py
07/04/2020  12:55 PM               580 test.py
07/03/2020  08:25 PM    <DIR>          __pycache__
               2 File(s)          7,391 bytes
               3 Dir(s)  1,487,446,302,720 bytes free

Process Finished

C:\Users\nj2u2\Desktop\test>python test.py
command? python


在最后一个命令之后python,它只是挂在print(ps.stdout.read()).

我想知道它为什么挂起,以及如何修复它。

标签: pythonsubprocesspopen

解决方案


communicate方法只能用于非交互式命令,因为它发送一次性输入,然后等待子进程终止。这就是它只能与你所说的一次性命令一起工作的原因。

但要注意,管道不支持终端规则,其中读取调用自动刷新输出,并且新行导致读取立即返回。因此,没有任何东西可以保证您可以使用它来为 python CLI 解释器提供交互式 IO。管道只是流,可以缓冲,因此您可以确保所有输入都将被传递,并且当输出通道关闭时(即当子流程命令终止时)您将收到所有输出。输入和输出混合的方式取决于子流程命令的编程方式。如果它愿意在读取之前刷新其输出,并且您在代码中执行相同操作,那么交互式处理是可能的,但如果不这样做,则无法期望在每行结束后收到一些东西。


推荐阅读