python check_output 失败,退出状态为 1,但 Popen 对同一命令有效

python check_output fails with exit status 1 but Popen works for same command

用于识别 Xcode 在 Mac 上是否为 运行 的命令:cmd = "ps -ax | grep -v grep | grep Xcode"

如果 Xcode 不是 运行,那么上面的命令可以很好地与 subprocess 模块的 Popen 方法一起使用,但是会引发一个 CalledProcessErrorcheck_output 方法。我试图通过以下代码检查 stderr,但未能获得适当的信息来理解原因。

from subprocess import check_output, STDOUT, CalledProcessError

psCmd = "ps -ax | grep -v grep | grep Xcode"
o = None
try:
    o = check_output(psCmd, stderr=STDOUT, shell=True)
except CalledProcessError as ex:
    print 'Error:', ex, o

异常信息如下:

Error: Command 'ps -ax | grep -v grep | grep Xcode' returned non-zero exit status 1 None

问题:为什么上述命令对 Popen 有效,但对 check_output 无效?

注意:如果 Xcode 是 运行。

,则命令适用于这两种方法

来自 Python 文档:"If the return code was non-zero it raises a CalledProcessError."。这就是当 Xcode 不是 运行 时发生在你身上的事情;最后的 grep Xcode 以非零状态退出,因为 grep 找不到您要查找的字符串 Xcode。因此,check_output() 将引发异常。

顺便说一句,我在 the Python subprocess documentation 上找到了这个。

如果你的 grep 命令 grep Xcode return 没有结果那么命令的 returncode 将是非零的,这就是为什么 check_output 调用 CalledProcessError,这就是您在 print 命令

的输出中看到的内容

要获得命令的输出,无论是错误还是成功,请使用以下代码:-

#!/usr/bin/python
from subprocess import check_output, STDOUT, CalledProcessError

psCmd = "ps -aef | grep -v grep | grep Xcode"
o = None
o = check_output(psCmd+";exit 0", stderr=STDOUT, shell=True)

check_output 只会在 return 代码为 0 时向您显示命令的输出,否则它会调用异常。

check_output 的目的是确保您运行 成功完成命令。如果 grep Xcode 没有 return 成功,应该 失败。

无论如何,在 Python 中搜索您想要的东西会简单得多。

output = check_output(['ps', '-ax'], shell=False)
if 'Xcode' in output:
    print('Xcode appears to be running')

这比 shell 版本有额外的(非常小的)好处,如果 ps 由于某种原因失败,它实际上会失败。当 shell 不在管道末尾时,它会简单地忽略 ps 的退出代码。

check_output() 按预期工作。这是它在 Popen():

方面的简化实现
def check_output(cmd):
    process = Popen(cmd, stdout=PIPE)
    output = process.communicate()[0]
    if process.returncode != 0:
        raise CalledProcessError(process.returncode, cmd, output=output)
    return output

grep returns 1 如果它没有找到任何东西,即,如果 Xcode 不是 运行.

注意:如实现所示,即使发生异常也能得到输出:

#!/usr/bin/env python
from subprocess import check_output, STDOUT, CalledProcessError

cmd = "ps -ax | grep -v grep | grep Xcode"
try:
    o = check_output(cmd, stderr=STDOUT, shell=True)
    returncode = 0
except CalledProcessError as ex:
    o = ex.output
    returncode = ex.returncode
    if returncode != 1: # some other error happened
        raise

您可能可以使用 pgrep -a Xcode 命令代替(注意:以 p 开头)或使用 psutil 模块作为可移植代码:

#!/usr/bin/env python
import psutil # $ pip install psutil

print([p.as_dict() for p in psutil.process_iter() if 'Xcode' in p.name()])