我在使用 subprocess.Popen.communicate() 时遇到了一个奇怪的问题。对于背景,我想从我的 python 脚本执行一个应用程序。当我从命令行运行程序时,我是这样做的(UNIX):
$ echo "输入文本" | /路径/到/我的应用程序
从我的脚本中,我还想将输入通过管道传输到应用程序中。所以,我尝试了以下方法。但是当我尝试使用通信()发送输入时,出现“管道损坏”错误:
>>> cmd = ['/path/to/myapp']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE)
>>> out,err = p.communicate('输入文本')
回溯(最近一次调用最后一次):
文件“”,第 1 行,在
文件“/usr/lib/python2.5/subprocess.py”,第 670 行,在通信中
返回 self._communicate(input)
文件“/usr/lib/python2.5/subprocess.py”,第 1223 行,在 _communicate
bytes_written = self._write_no_intr(self.stdin.fileno(), buffer(input, input_offset, 512))
文件“/usr/lib/python2.5/subprocess.py”,第 1003 行,在 _write_no_intr
返回 os.write(fd, s)
OSError: [Errno 32] 管道损坏
更奇怪的是,如果我省略输入数据,我不会收到任何错误。但是,这并不是一个很好的解决方法,因为应用程序需要输入才能工作。
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, stdin=subprocess.PIPE) >>> out,err = p.communicate() >>> 打印出来 [来自 myapp 的关于缺少输入的错误]
知道我错过了什么吗?
您的观察表明 myapp 在未读取(所有)输入的情况下终止。对 myapp 一无所知,这很难确认,但请考虑例如
$ echo 'hello world' | tr 'l' 'L'
heLLo worLd
Run Code Online (Sandbox Code Playgroud)
现在...:
>>> 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
Run Code Online (Sandbox Code Playgroud)
因为...:
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE)
>>> /usr/bin/tr: missing operand
Try `/usr/bin/tr --help' for more information.
Run Code Online (Sandbox Code Playgroud)
如果我们修复这个错误:
>>> 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
Run Code Online (Sandbox Code Playgroud)
...它解决了一切。如果您省略 stderr 重定向,会发生什么 - 您是否可能看到来自 myapp 的任何错误消息...?