Подтвердить что ты не робот

Получить код выхода и stderr из вызова подпроцесса

Я прочитал функции, предоставляемые подпроцессом - call, check_call, check_output, и понял, как каждый работает и отличается функциональностью друг от друга. В настоящее время я использую check_output, поэтому я могу получить доступ к stdout и использовать "try block", чтобы поймать исключение, следующим образом:

# "cmnd" is a string that contains the command along with it arguments. 
try:
    cmnd_output = check_output(cmnd, stderr=STDOUT, shell=True, timeout=3, universal_newlines=True);                         
except CalledProcessError:                                                                                                   
    print("Status : FAIL")                                                                                                   
print("Output: \n{}\n".format(cmnd_output))                                                                                  

Проблема, с которой я сталкиваюсь, - это когда генерируется исключение, "cmnd_output" не инициализирован и не имеет доступа к stderr, и появляется следующее сообщение об ошибке:

print("Output: \n{}\n".format(cmnd_output))
UnboundLocalError: local variable 'cmnd_output' referenced before assignment

Я думаю, это потому, что исключение заставляет "check_output" немедленно освобождаться без дальнейшей обработки, а также назначение "cmnd_output" в блоке try. Пожалуйста, поправьте меня, если я ошибаюсь.

Есть ли способ получить доступ к stderr (это нормально, если он отправлен в stout) и иметь доступ к коду выхода. Я могу вручную проверять пропуск/сбой на основе кода выхода без исключения.

Спасибо, Ахмед.

4b9b3361

Ответ 1

Попробуйте эту версию:

import subprocess
try:
    output = subprocess.check_output(
        cmnd, stderr=subprocess.STDOUT, shell=True, timeout=3,
        universal_newlines=True)
except subprocess.CalledProcessError as exc:
    print("Status : FAIL", exc.returncode, exc.output)
else:
    print("Output: \n{}\n".format(output))

Таким образом вы будете печатать вывод только в том случае, если вызов был успешным. В случае CalledProcessError вы печатаете код возврата и вывод.

Ответ 2

Принятое решение охватывает случай, когда вы нормально смешиваете stdout и stderr, но в случаях, когда дочерний процесс (по какой-либо причине) решает использовать stderr IN ADDITION для stdout для (например, для вывода некритического предупреждения), то данное решение может быть нежелательным.

Например, если вы будете выполнять дополнительную обработку на выходе, например, преобразование в JSON, и вы смешаете в stderr, тогда общий процесс завершится неудачно, так как вывод не будет чистым JSON из-за добавленного stderr.

В этом случае я нашел следующее:

cmd_args = ... what you want to execute ...

pipes = subprocess.Popen(cmnd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
std_out, std_err = pipes.communicate()

if pipes.returncode != 0:
    # an error happened!
    err_msg = "%s. Code: %s" % (std_err.strip(), pipes.returncode)
    raise Exception(err_msg)

elif len(std_err):
    # return code is 0 (no error), but we may want to
    # do something with the info on std_err
    # i.e. logger.warning(std_err)

# do whatever you want with std_out
# i.e. json.loads(std_out)

Ответ 3

почему бы не инициализировать varible cmnd_output перед операцией try? Таким образом, он будет работать так, как вы ожидаете. Следующая строка будет работать, просто добавьте ее выше инструкции try:

cmnd_output = ''