subprocess.Popen.communicate() 中 stdin 出现破损管道

6 投票
1 回答
11417 浏览
提问于 2025-04-15 18:03

我在使用subprocess.Popen.communicate()的时候遇到了一个奇怪的问题。先说一下背景,我想从我的Python脚本中执行一个应用程序。当我在命令行中运行这个程序时,我是这样做的(在UNIX系统上):

$ echo "input text" | /path/to/myapp

在我的脚本中,我还想把输入数据传给这个应用程序。所以,我尝试了以下方法。但是,当我用communicate()发送输入时,出现了“broken pipe”的错误:

>>> cmd = ['/path/to/myapp']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE)
>>> out,err = p.communicate('input text')
Traceback (most recent call last):
  File "", line 1, in 
  File "/usr/lib/python2.5/subprocess.py", line 670, in communicate
    return self._communicate(input)
  File "/usr/lib/python2.5/subprocess.py", line 1223, in _communicate
    bytes_written = self._write_no_intr(self.stdin.fileno(), buffer(input, input_offset, 512))
  File "/usr/lib/python2.5/subprocess.py", line 1003, in _write_no_intr
    return os.write(fd, s)
OSError: [Errno 32] Broken pipe

更奇怪的是,如果我不提供输入数据,就不会出现任何错误。不过,这并不是一个好的解决办法,因为这个应用程序需要输入才能正常工作。

>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE)
>>> out,err = p.communicate()
>>> print out
[error from myapp regarding lack of input]

你知道我缺少了什么吗?

1 个回答

3

你的观察表明,myapp在没有读取(所有)输入的情况下就结束了。虽然我对myapp一无所知,无法确认这一点,但可以考虑以下例子:

$ echo 'hello world' | tr 'l' 'L'
heLLo worLd

现在...:

>>> cmd = ['/usr/bin/tr']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE)
>>> out,err = p.communicate('hello world')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.5/subprocess.py", line 668, in communicate
    return self._communicate(input)
  File "/usr/lib/python2.5/subprocess.py", line 1218, in _communicate
    bytes_written = self._write_no_intr(self.stdin.fileno(), buffer(input, input_offset, 512))
  File "/usr/lib/python2.5/subprocess.py", line 997, in _write_no_intr
    return os.write(fd, s)
OSError: [Errno 32] Broken pipe

因为...:

>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
>>> /usr/bin/tr: missing operand
Try `/usr/bin/tr --help' for more information.

如果我们修复这个错误:

>>> cmd = ['/usr/bin/tr', 'l', 'L']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
>>> out,err = p.communicate('hello world')>>> print out
heLLo worLd
>>> print err
None

...这就解决了所有问题。如果你不进行错误输出重定向,会发生什么呢?你是否能看到myapp的任何错误信息呢...?

撰写回答