Python 保存子进程命令的错误消息

Python 保存子进程命令的错误消息,python,bash,error-handling,subprocess,Python,Bash,Error Handling,Subprocess,使用子流程运行bash命令时,可能会遇到命令无效的情况。在这种情况下,bash将返回一个错误消息。我们怎样才能抓住这个信息?我想将此消息保存到日志文件中。 下面是一个示例,我尝试列出一个不存在的目录中的文件 try: subprocess.check_call(["ls", "/home/non"]) df = subprocess.Popen(["ls", "/home/non"], stdout=subprocess.PIPE) output, er

使用子流程运行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:cannotaccess/home/non:No这样的文件或目录”。如何获取此错误消息?except行捕获的错误明显不同,它表示“命令'['ls','/home/non']'返回非零退出状态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
如果您希望邮件出现在中,除了:

try:
    check_call(["ls", "/home/non"])
    df = Popen(["ls", "/home/non"], stdout=PIPE)
    output, err = df.communicate()
except CalledProcessError as e:
    print(e.message)
对于Python2.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)
“ls:无法访问/home/non:没有这样的文件或目录”是由
ls
命令生成的,not
bash
在这里

如果要使用异常处理来处理不存在的文件,请使用
子流程。检查\u output()

输出
我认为您需要重定向这两个:即
stdout=subprocess.PIPE,stderr=subprocess.stdout
,然后错误消息将出现在
err
@martineau中,谢谢您的建议。我刚刚检查过,如果将“stderr=…”添加到Popen中,则输出错误消息。如果有,我更喜欢通过excpet线路捕捉这条信息。有什么想法吗?要做到这一点,您需要进程间通信。因为
subprocess.Popen()
可以启动任何类型的其他难以启动的进程。关于您唯一的常规选项是
returncode
和管道。考虑使用<代码>子进程。CHECKOLUTION < /COD>而不是<代码> Popen < /代码>。是否有可能用“除行”来捕获此消息?@卢克,是的,只需捕获<代码> CalledProcessError < /代码>并打印大量消息。不幸的是,我得到了这个“”弃用警告:BaseException.message从Python 2.6开始就已弃用“.你在抓什么?还有什么版本的python?我使用的是Python2.6.6,只是出现了一个错误。test.py:15:DeprecationWarning:BaseException.message从Python 2.6 print e.message开始就被弃用了。为了澄清起见,这是一种访问全局Python会话中某些现有子进程“
stderr
的方法,对吗?不是将错误消息发送到创建的文本文件(如Cunningham的答案描述),而是@Coolio2654
stderr
参数在这里正常工作。如果要将stderr保存到文件,可以传递文件对象(使用有效的
.fileno()
)。
#!/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