【问题标题】:python subprocess multiple stdin.write and stdout.readpython子进程多个stdin.write和stdout.read
【发布时间】:2016-01-23 15:39:54
【问题描述】:

感谢您花时间回答问题。我正在玩 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

如果我将 test.py 替换为像“cat”这样的标准 linux 命令,一切都会按预期工作。

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

【问题讨论】:

标签: python python-3.x pipe subprocess


【解决方案1】:

一般来说,你应该use pexpect for interactive programs (dialog-based interactions)

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

注意:

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

输出

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

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

它可以工作,但它很脆弱,请阅读Q: Why not just use a pipe (popen())?use pexpect instead


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

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

输出是一样的(如上图)。

【讨论】:

  • 非常感谢塞巴斯蒂安的详细解释! :)。如何阅读多行?使用 cat.stdout.readline() 会永远挂起?
  • @waka-waka-waka:两个代码示例都已经读了多行
  • 谢谢,我的问题更多的是关于行,我不确定要读多少行,我什么时候休息?测试程序可能会打印 1 行或更多行...
  • check_output() 基于解决方案读取所有输出,无论子进程产生多少行。
  • 为了更清楚,假设孩子没有在屏幕上打印任何东西,在这种情况下 .readline() 将永远挂起?
猜你喜欢
  • 2014-02-04
  • 2012-04-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-19
  • 2013-01-04
相关资源
最近更新 更多