Skip to main content
 首页 » 编程设计

python之Subprocess.Popen 在解释器、可执行脚本中的行为不同

2025年05月04日10shangdawei

假设您有以下内容:

command = shlex.split("mcf -o -q -e -w %s %s" % (SOLFILE, NETFILE)) 
task = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
stdout, stderr = task.communicate() 
print "stdout: %s" % stdout #debugging 
print "stderr: %s" % stderr #debugging 
if stderr: 
    sys.exit("MCF crashed on %s" % NETFILE) 

没有必要知道 mcf 是什么,除了它是一个 C 程序,如果没有给它一个可满足的网络文件就会溢出。 (为什么我不能确保所有的网络文件都是可满足的?好吧,因为检查它的最简单方法是将它提供给 mcf 并查看它是否溢出......)

无论如何,当我在可执行脚本中运行它时,task.communicate() 似乎没有在 stdout 和 stderr 中存储任何内容。 (准确地说,我得到 stdout == stderr == ''。)相反,来自 mcf 的 stderr 流似乎“泄漏”到终端,而不是被子进程管道捕获。下面是一些示例输出来说明:

Netfile: facility3cat_nat5000_wholesaler_capacitation_test_.net 
Solfile: facility3cat_nat5000_wholesaler_capacitation_test_.sol 
*** buffer overflow detected ***: mcf terminated 
======= Backtrace: ========= 
... 
...[fifty lines of Linda Blair-esque output]... 
... 
stdout: None 
stderr:  
...[program continues, since stderr did not evaluate to True]... 

这仅在从命令行运行脚本时失败。当我在解释器中逐行执行时,stdout 和 stderr 被正确分配:

>>> task = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE) 
>>> stdout, stderr = task.communicate() 
>>> stderr 
'*** buffer overflow detected ***: mcf terminated\n======= Backtrace: =========\n' 
...[more headspinning and vomit]... 

谁能帮我理解为什么这在解释器中有效,但在执行时却无效?提前致谢!

请您参考如下方法:

我写了一个小测试脚本来测试 subprocess 模块。

#!/bin/bash 
 
echo echo to stderr 1>&2 
echo echo to stdout 

然后我写了一个调用它的小 Python 脚本:

#!/usr/bin/python 
 
import subprocess 
 
command = ('./joe.sh',) 
task = subprocess.Popen(command, stdout=subprocess.PIPE, 
                                 stderr=subprocess.PIPE) 
stdout, stderr = task.communicate() 
print 'stdout == %r\nstderr == %r' % (stdout, stderr) 

运行它的输出看起来就像这样:

$ python joe.py  
stdout == 'echo to stdout\n' 
stderr == 'echo to stderr\n' 

在 ipython 中运行相同序列的输出是相同的。

因此 subprocess 模块以您期望的方式运行,而不是它在您的问题中的运行方式。我认为 subprocess 模块以外的东西一定是这里的错误,因为你正在做的对我有用。

我正在运行 Python 2.7,所以另一种可能性是 subprocess 模块的旧版本中可能存在某种奇怪的错误。