【问题标题】:python check_output fails with exit status 1 but Popen works for same commandpython check_output 失败,退出状态为 1,但 Popen 适用于相同的命令
【发布时间】:2015-04-24 20:33:32
【问题描述】:

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

如果 Xcode 没有运行,那么上面的命令适用于 subprocess 模块的 Popen 方法,但使用 check_output 方法引发 CalledProcessError。我试图通过以下代码检查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 中进行 grep 处理会好得多。
  • 即使我在python中处理输出,我也必须使用subprocess模块。所以我认为这是在bash end 完成所有工作的好方法。

标签: python subprocess popen


【解决方案1】:

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 如果没有找到任何东西,则返回 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()])

【讨论】:

  • 我现在明白了,为什么 check_output 表现得如此。检查返回码很酷。我会将您的想法与errno一起使用。一些疑问1. 为什么我们必须在try 块中初始化returncode 值为0? 2。我们不能直接将ex.returncodeif 条件中的值1 进行比较吗?它是否有某种目的,我还没有理解。
  • returncode 设置在 try/except 中,以便 1. 向您展示如果 check_output() 没有引发异常,它始终为零 2. 两个分支(有和没有异常)设置两个变量:无论 Xcode 是否正在运行,您都可以在代码后使用 oreturncode
【解决方案2】:

来自 Python 文档:“如果返回码不为零,则会引发 CalledProcessError。”。这就是 Xcode 不运行时发生的情况;最后的grep Xcode 以非零状态退出,因为grep 找不到您要查找的字符串Xcode。因此,check_output() 将引发异常。

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

【讨论】:

  • 我不这么认为。如果我在没有启动 Xcode 的情况下在终端中运行此命令并检查 errno 变量,它仍然保持值 0。要检查 errno,我使用了 echo "$?"。
  • 嗯...当我尝试ps -aef | grep -v grep | grep Xcode ; echo $? 时,我得到输出:1
  • @DeepakrajHR 你的意思是即使 Xcode 没有启动你的 grep 命令正在寻找它?您显示的错误消息 Error: Command 'ps -ax | grep -v grep | grep Xcode' returned non-zero exit status 1 None 是您的 python 脚本的输出,因为您已经处理了代码中的异常
  • Xcode 未运行时的终端输出$ ps -ax | grep -v grep | grep Xcode $ echo "$?" 0 $ Xcode 运行时的终端输出$ ps -ax | grep -v grep | grep Xcode 13784 ?? 0:02.34 /Applications/Xcode.app/Contents/MacOS/Xcode $ echo "$?" 0 $ 所以我的意思是,我不认为错误代码 1 来自这里。我还缺少其他东西。
  • 没关系,引号是无害的(实际上是一种很好的形式,尤其是在您不确定引用时)。
【解决方案3】:

如果您的 grep 命令 grep Xcode 没有返回任何结果,那么该命令的 returncode 将非零,这就是 check_output 调用 CalledProcessError 的原因,这就是您在 @987654327 的输出中看到的@命令

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

#!/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 只会在返回码为0 时显示命令的输出,否则会调用异常。

【讨论】:

  • 请查看我对 Karel Kubat 回答的评论
  • 这是一个好主意,如link 所示。但是为什么我从 python 脚本中得到错误代码为 1,而从终端中得到 0。无论如何,现在我正在使用 Popen 来解决问题。但问题仍然存在:-(
  • 我得到了答案。现在我正在使用这种方式。但是我现在想知道,如果命令由于其他未知原因而失败怎么办。我认为这也会因为exit 0 而绕过。有没有办法捕捉这些异常。
  • 这不是一个理智的答案。如果您不想检查命令的结果代码,请不要使用check_output
  • exit 0 不好。它忽略错误。你可以get the output even if an exception happens
【解决方案4】:

check_output 的目的是确保您运行的命令成功完成。如果grep Xcode 没有返回成功,则假定失败。

无论如何,用 Python 搜索你想要的东西会简单得多。

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-15
    • 1970-01-01
    • 2017-05-20
    • 2023-03-08
    • 1970-01-01
    相关资源
    最近更新 更多