保存子进程命令的错误信息

Posted

技术标签:

【中文标题】保存子进程命令的错误信息【英文标题】:Save error message of subprocess command 【发布时间】:2015-06-17 07:23:09 【问题描述】:

当使用子进程运行 bash 命令时,我可能会遇到命令无效的情况。在这种情况下,bash 将返回错误消息。我们怎样才能捕捉到这个消息?我想将此消息保存到日志文件中。 以下是一个示例,我尝试列出不存在目录中的文件。

try:
    subprocess.check_call(["ls", "/home/non"]) 
    df = subprocess.Popen(["ls", "/home/non"], stdout=subprocess.PIPE)        
    output, err = df.communicate()
    # process outputs
except Exception as error:        
    print error
    sys.exit(1)

Bash 会打印“ls: cannot access /home/non: No such file or directory”。我怎样才能得到这个错误信息? except 行捕获的错误明显不同,它说“命令'['ls','/home/non']'返回非零退出状态2”。

【问题讨论】:

我认为你需要重定向两个:即stdout=subprocess.PIPE, stderr=subprocess.STDOUT,然后错误消息将在err @martineau 感谢您的建议。我刚刚检查过,如果将“stderr=...”添加到 Popen,则会在输出中显示错误消息。如果有的话,我更喜欢通过 excpet 行捕获此消息的方法。有什么想法吗? 为此,您需要进程间通信。因为subprocess.Popen() 可以启动任何其他类型的困难进程。关于您唯一的常规选项是returncode 和管道。考虑使用subprocess.check_output 而不是Popen 【参考方案1】:

“ls: cannot access /home/non: No such file or directory”是由ls命令生成的,不是bash这里。

如果您想使用异常处理来处理不存在的文件,请使用subprocess.check_output()

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

try:
    output = check_output(['ls', 'nonexistent'], stderr=STDOUT)
except CalledProcessError as exc:
    print(exc.output)
else:
    assert 0

输出

ls: cannot access nonexistent: No such file or directory

【讨论】:

只是为了澄清的目的,这是一种在全局 Python 会话中访问一些 现有 子进程'stderr 的方法,对吗?而不是将错误消息发送到创建的文本文件,如坎宁安的回答所描述的? @Coolio2654 stderr 参数在这里照常工作。如果您想将 stderr 保存到文件中,可以传递一个文件对象(带有有效的 .fileno())。【参考方案2】:

您可以将 stderr 重定向到文件对象:

from subprocess import PIPE, CalledProcessError, check_call, Popen

with open("log.txt", "w") as f:
    try:
        check_call(["ls", "/home/non"], stderr=f)
        df = Popen(["ls", "/home/non"], stdout=PIPE)
        output, err = df.communicate()
    except CalledProcessError as e:
        print(e)
        exit(1)

输出到 log.txt:

ls: cannot access /home/non: No such file or directory

如果你想要在except中的消息:

try:
    check_call(["ls", "/home/non"])
    df = Popen(["ls", "/home/non"], stdout=PIPE)
    output, err = df.communicate()
except CalledProcessError as e:
    print(e.message)

对于 python 2.6,e.message 将不起作用。您可以使用 python 2.7 的 check_output 的类似版本,它适用于 python 2.6:

from subprocess import PIPE, CalledProcessError, Popen

def check_output(*args, **kwargs):
    process = Popen(stdout=PIPE, *args, **kwargs)
    out, err = process.communicate()
    ret = process.poll()
    if ret:
        cmd = kwargs.get("args")
        if cmd is None:
            cmd = args[0]
        error = CalledProcessError(ret, cmd)
        error.out = out
        error.message = err
        raise error
    return out

try:
    out = check_output(["ls", "/home"], stderr=PIPE)
    df = Popen(["ls", "/home/non"], stdout=PIPE)
    output, err = df.communicate()
except CalledProcessError as e:
    print(e.message)
else:
    print(out)

【讨论】:

是否可以通过 except 行捕获此消息? @Luke,是的,只需抓住CalledProcessError 并打印消息 非常感谢。不幸的是,我得到了这个”“DeprecationWarning: BaseException.message 自 Python 2.6 起已被弃用”。 你在抓什么?还有什么版本的python? 我用的是python 2.6.6,刚刚报错。 test.py:15: DeprecationWarning: BaseException.message 自 Python 2.6 起已弃用 print e.message

以上是关于保存子进程命令的错误信息的主要内容,如果未能解决你的问题,请参考以下文章

linux中的进程于计划任务管理

linux中进程和计划任务管理

如何获取shell命令输出的错误信息

启动包含管道命令的子进程时找不到文件错误

如何获取子进程的输出

进程与计划任务管理