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

2024-01-11

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

while True:
    print("enter something...")
    x = input()
    print(x)
    time.sleep(1)

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

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())

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

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

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

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


一般来说,你应该use pexpect用于交互式程序(基于对话的交互) https://stackoverflow.com/tags/subprocess/info.

您的具体问题可能是由 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='')

Note:

  • sys.exectable是当前的 python 可执行文件(在本例中为 Python 3)
  • universal_newlines=True启用文本模式(否则,cat.stdin and cat.stdout使用字节,而不是字符串)
  • -u使孩子的输出行缓冲(否则,在子进程刷新其内部标准输出缓冲区之前,您将看不到任何内容 https://stackoverflow.com/q/20503671/4279)
  • the with-语句关闭管道并等待子进程退出。

这是对应的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)

Output

enter something...hello, world!
enter something...and another line
enter something...

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

它可以工作,但很脆弱,请阅读问:为什么不直接使用管道(popen())? http://pexpect.readthedocs.org/en/latest/FAQ.html#whynotpipe and use pexpect instead https://stackoverflow.com/a/23795689/4279.


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

#!/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='')

此版本要求子进程正确处理 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)

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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python 子进程多个 stdin.write 和 stdout.read 的相关文章

随机推荐