检查 CalledProcessError 的输出

Posted

技术标签:

【中文标题】检查 CalledProcessError 的输出【英文标题】:check output from CalledProcessError 【发布时间】:2011-11-26 09:05:56 【问题描述】:

我正在使用 pythons subprocess 模块中的 subprocess.check_output 来执行 ping 命令。这是我的做法:

output = subprocess.check_output(["ping","-c 2 -W 2","1.1.1.1")

它引发了一个 CalledProcessError 并说输出是函数的参数之一。谁能帮助我如何阅读该输出。我想将输出读入字符串并解析它。例如,如果 ping 返回

100% 丢包

我需要捕捉到这一点。如果还有其他更好的方法..请提出建议。谢谢。

【问题讨论】:

// ,您能否在此问题中包含指向此文档的链接,docs.python.org/2/library/…? 最重要的是关闭您打开的任何括号:对于每个 [, 或 ( 必须有一个 ), 或 ] 然后将您的 shell 命令想象为一个字符串并在其上执行 .split(' ')并将结果列表作为输入传递给check_output() 【参考方案1】:

根据Python os module documentation os.popen 自 Python 2.6 以来已被弃用。

我认为现代 Python 的解决方案是使用 subprocess 模块中的 check_output()。

来自subprocess Python documentation:

subprocess.check_output(args, *, stdin=None, stderr=None, shell=False, universal_newlines=False) 运行带参数的命令并将其输出作为字节字符串返回。

如果返回码不为零,则会引发 CalledProcessError。 CalledProcessError 对象将在 returncode 属性中具有返回码,在输出属性中具有任何输出。

如果您在 Python 2.7(或更高版本)中运行以下代码:

import subprocess

try:
    print subprocess.check_output(["ping", "-n", "2", "-w", "2", "1.1.1.1"])
except subprocess.CalledProcessError, e:
    print "Ping stdout output:\n", e.output

您应该会看到如下所示的输出:

Ping stdout output:

Pinging 1.1.1.1 with 32 bytes of data:
Request timed out.
Request timed out.

Ping statistics for 1.1.1.1:
Packets: Sent = 2, Received = 0, Lost = 2 (100% loss),

可以解析 e.output 字符串以满足 OP 的需求。

如果你想要返回码或其他属性,它们在 CalledProccessError 中,可以通过 pdb 单步执行来查看

(Pdb)!dir(e)   

['__class__', '__delattr__', '__dict__', '__doc__', '__format__',
 '__getattribute__', '__getitem__', '__getslice__', '__hash__', '__init__',
 '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
 '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', 
 '__unicode__', '__weakref__', 'args', 'cmd', 'message', 'output', 'returncode']

【讨论】:

注意:如果不使用输出,请使用 check_call 而不是 check_output。如果您知道该命令在普通情况下返回非零退出状态,那么您可以直接使用p = Popen() 并调用p.wait()output, err = p.communicate()(如果您需要输出)以避免引发不必要的异常 @J.F.Sebastian 我尝试使用 subprocess.call 但这会返回一个 int (1) 而不是我的命令的输出:/ @Loretta: 注意:“如果你不使用输出” 在我的评论中。如果subprocess.call() 返回1,则表示您的命令运行但失败:通常表示错误,在这种情况下使用check_* 函数引发异常。如果您的情况不是错误(例如,对于grep,这意味着“未找到”);捕捉CalledProcessError或直接使用Popen及其方法。 感谢您加入 try except。 代码 sn-p 仅适用于 Python 2.7,不适用于 Python 3,因此您可能应该从它前面的语句中删除“(或更高版本)”。【参考方案2】:

如果您想找回 stdout 和 stderr(包括在发生时从 CalledProcessError 中提取它),请使用以下内容:

import subprocess

def call_with_output(command):
    success = False
    try:
        output = subprocess.check_output(command, stderr=subprocess.STDOUT).decode()
        success = True 
    except subprocess.CalledProcessError as e:
        output = e.output.decode()
    except Exception as e:
        # check_call can raise other exceptions, such as FileNotFoundError
        output = str(e)
    return(success, output)

call_with_output(["ls", "-l"])

这是 Python 2 和 3 兼容的。

如果您的命令是字符串而不是数组,请在其前面加上:

import shlex
call_with_output(shlex.split(command))

【讨论】:

e.output.decode("utf-8") 在我这边返回"" @alper 进程可能会失败而不会生成任何输出。这是一个简单的例子:call_with_output(["false"])【参考方案3】:

在参数列表中,每个条目必须独立。使用

output = subprocess.check_output(["ping", "-c","2", "-W","2", "1.1.1.1"])

应该可以解决您的问题。

【讨论】:

我仍然收到错误消息。该错误表示输出是 CalledProcessError 的参数之一。我尝试使用 try except...,但这也没有用。 @ash 你能发一个short reproducible example 来证明except 不工作吗? try:subprocess.check_output(["ping", "-c","2", "-W","2", "1.1.1.1") 除了 CalledProcessError as e: print str (例如输出)。这是我的 try catch 块 @ash, jfyi 它应该是except subprocess.CalledProcessError 这没有回答问题。【参考方案4】:

我遇到了同样的问题,发现documentation 有这种场景的示例(我们将 STDERR 写入 STDOUT 并始终以返回码 0 成功退出)而不会导致/捕获异常。

output = subprocess.check_output("ping -c 2 -W 2 1.1.1.1; exit 0", stderr=subprocess.STDOUT, shell=True)

现在,您可以使用标准字符串函数find 来检查输出字符串output

【讨论】:

【参考方案5】:

Thanx @krd,我正在使用您的错误捕获过程,但必须更新 print 和 except 语句。我在 Linux Mint 17.2 上使用 Python 2.7.6。

此外,还不清楚输出字符串的来源。 我的更新:

import subprocess

# Output returned in error handler
try:
    print("Ping stdout output on success:\n" + 
           subprocess.check_output(["ping", "-c", "2", "-w", "2", "1.1.1.1"]))
except subprocess.CalledProcessError as e:
    print("Ping stdout output on error:\n" + e.output)

# Output returned normally
try:
    print("Ping stdout output on success:\n" + 
           subprocess.check_output(["ping", "-c", "2", "-w", "2", "8.8.8.8"]))
except subprocess.CalledProcessError as e:
    print("Ping stdout output on error:\n" + e.output)

我看到这样的输出:

Ping stdout output on error:
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.

--- 1.1.1.1 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1007ms


Ping stdout output on success:
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=59 time=37.8 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=59 time=38.8 ms

--- 8.8.8.8 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 37.840/38.321/38.802/0.481 ms

【讨论】:

【参考方案6】:

仅当主机响应 ping 时才会返回 true。适用于windows和linux

def ping(host):
    """
    Returns True if host (str) responds to a ping request.
    NB on windows ping returns true for success and host unreachable
    """
    param = '-n' if platform.system().lower()=='windows' else '-c'
    result = False
    try:
        out = subprocess.check_output(['ping', param, '1', host])
        #ping exit code 0
        if 'Reply from '.format(host) in str(out):
            result = True          
    except  subprocess.CalledProcessError:
        #ping exit code not 0
            result = False
    #print(str(out))
    return result

【讨论】:

以上是关于检查 CalledProcessError 的输出的主要内容,如果未能解决你的问题,请参考以下文章

忽略 CalledProcessError

`asyncio` 模块中是不是有 `CalledProcessError` 的类似物?

subprocess.CalledProcessError:返回非零退出状态 0

Buildozer 错误,CalledProcessError (Kivy)

CalledProcessError:命令'['convert','--version']'返回非零退出状态1

subprocess.CalledProcessError 返回非零退出状态 1