Сохранить сообщение об ошибке команды subprocess

при выполнении команды bash с помощью подпроцесса я могу столкнуться с ситуацией, когда команда недопустима. В этом случае bash вернет ошибку messsage. Как мы можем поймать это сообщение? Я хотел бы сохранить это сообщение в файл журнала. Ниже приведен пример, где я пытаюсь перечислить файлы в несуществующем каталоге.

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: не может получить доступ /home/non: нет такого файла или каталога". Как я могу получить это сообщение об ошибке? Ошибка, пойманная исключением строка явно отличается, в ней говорится: "Command '['ls', '/home/non']' возвращено ненулевое состояние выхода 2".

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)

вывод в лог.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)

"ls: не удается получить доступ / home / non: нет такого файла или каталога" созданный , не 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