python 子进程多个 stdin.write 和 stdout.read

wak*_*aka 5 python subprocess pipe python-3.x

感谢您抽出时间回答问题。我正在使用 Python 3.4,并且有两个简单的 python 程序。一是一个名为 test.py 的程序,它接受用户输入并打印一些内容。

while True:
    print("enter something...")
    x = input()
    print(x)
    time.sleep(1)
Run Code Online (Sandbox Code Playgroud)

为了将输入发送到该程序,我有另一个使用子进程的程序:

from subprocess import Popen, PIPE

cat = Popen('python test.py', shell=True, stdin=PIPE, stdout=PIPE)
cat.stdin.write("hello, world!\n")
cat.stdin.flush()
print(cat.stdout.readline())

cat.stdin.write("and another line\n")
cat.stdin.flush()
print(cat.stdout.readline())
Run Code Online (Sandbox Code Playgroud)

但是,当我运行上面的程序时,出现错误:

enter something...

hello, world!
Traceback (most recent call last):
  File "/opt/test.py", line 9, in <module>
    x = input()
EOFError: EOF when reading a line
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
BrokenPipeError: [Errno 32] Broken pipe
Run Code Online (Sandbox Code Playgroud)

如果我用标准的 Linux 命令(如“cat”)替换 test.py,一切都会按预期进行。

有什么方法可以发送多个标准输入写入并读回多个标准输出吗?

jfs*_*jfs 5

一般来说,您应该用于pexpect交互式程序(基于对话框的交互)

您的具体问题可能是由 python 版本不匹配引起的(您认为您的代码是使用 Python 3 执行的,而实际上它可能是使用 Python 2 执行的)。第二个问题 ( EOFError) 是预期的:要么在子脚本中捕获它,要么为子脚本提供退出信号(我在下面的代码示例中使用空行)。

下面是一个在 Python 2 上严重失败的 Python 3 代码:

#!/usr/bin/env python3
import sys
from subprocess import Popen, PIPE

with Popen([sys.executable, '-u', 'test.py'], stdin=PIPE, stdout=PIPE,
           universal_newlines=True, bufsize=1) as cat:
    for input_string in ["hello, world!", "and another line", ""]:
        print(input_string, file=cat.stdin, flush=True)
        print(cat.stdout.readline(), end='')
Run Code Online (Sandbox Code Playgroud)

笔记:

这是相应的test.py

#!/usr/bin/env python3
import time

while True:
    x = input("enter something...")
    if not x: # exit if the input is empty
        break
    print(x)
    time.sleep(1)
Run Code Online (Sandbox Code Playgroud)

输出

enter something...hello, world!
enter something...and another line
enter something...
Run Code Online (Sandbox Code Playgroud)

注意:后面没有新行"enter something..."

它可以工作,但很脆弱,请阅读问:为什么不直接使用管道(popen())?使用pexpect.


如果输入是有限的并且不依赖于输出,那么您可以一次将其全部传递:

#!/usr/bin/env python3
import sys
from subprocess import check_output

output = check_output([sys.executable, 'test.py'],
                      input="\n".join(["hello, world!", "and another line"]),
                      universal_newlines=True)
print(output, end='')
Run Code Online (Sandbox Code Playgroud)

此版本要求子进程正确处理 EOF:

#!/usr/bin/env python3
import time

while True:
    try:
        x = input("enter something...")
    except EOFError:
        break # no more input

    print(x)
    time.sleep(1)
Run Code Online (Sandbox Code Playgroud)

输出是相同的(如上所示)。