2016-01-17 1 views
1

Мой скрипт python должен вызывать программу, обнаруживать, не удалось ли она (например, result != 0) и отправить вывод программы на оба stdout как обычный плюс файл журнала.Как использовать python subprocess.call, отправляя копию stdout в лог-файл, при обнаружении результата первой команды

My default shell is bash. Я использую Python 2.7.9

Для отправки вывода на стандартный вывод как и файл я обычно использую tee:

result = subprocess.call('some_program --an-option | tee -a ' + logfile , shell=True) 

Однако труба в Баш возвращает истину, даже если первая команда не , поэтому этот подход не может определить, не сработала ли команда.

Если я пытаюсь использовать set -o pipefail в команде (так что результат будет указывать, если первая команда не) так:

result = subprocess.call('set -o pipefail && some_program --an_option | tee -a ' + logfile , shell=True) 

Я получаю ошибку /bin/sh: 1: set: Illegal option -o pipefail

Есть ли способ python, чтобы вызвать команду, отправить вывод как в обычную консоль stdout, так и в файл журнала, и все еще определить, не сработала ли команда?

Примечание: мы должны продолжить отправку вывода some_program в stdout, поскольку stdout отправляется в websocket.

ответ

1

Я получаю ошибку/бен/ш: 1: набор: Illegal параметр -o pipefail

Pass executable='/bin/bash' иначе используется /bin/sh.

Вы могли бы реализовать tee в чистом Python:

#!/usr/bin/env python2 
import sys 
from subprocess import Popen, PIPE 

chunk_size = 1 << 13  
p = Popen(["some_program", "--an-option"], stdout=PIPE, bufsize=1) 
with p.stdout, open('logfile', 'ab') as logfile: 
    for chunk in iter(lambda: p.stdout.read(chunk_size), b''): 
     sys.stdout.write(chunk) 
     logfile.write(chunk) 
if p.wait() != 0: 
    raise Error 
0

Мое предпочтение было бы отправить stdout на трубу, а затем прочитать трубу в коде Python. Код Python может записывать в stdout, файл и т. Д. По мере необходимости. Это также позволит вам установить shell = False, поскольку установка его в True является потенциальной проблемой безопасности, как указано в документации.

0

Однако труба в Баш возвращает истину, даже если первая команда не удается, поэтому такой подход не в состоянии обнаружить, если команда не выполняется.

Это неправда.
Но я думаю, вы имеете в виду: код состояния выхода 'some_program --an-option | tee -a ' + logfile всегда равен 0, хотя и не выполняется в какой-либо части команды.

Ну, используя несколько команд (при использовании && или ||) или одновременное соединение нескольких команд по каналам вызывает недопустимый код состояния выхода при возврате.

Независимо от того, в команде: some_program --an-option | tee -a ' + logfile logfile не записан, если some_program не работает. Поэтому вам не нужно беспокоиться о коде выхода.

Во всяком случае, лучший способ сделать трубу вместе с подпроцессом создает Popen объектов анса обработку stdout и stdin:

импорта подпроцесс как зр

STATUS_OK = 0 
logfile = '/tmp/test.log' 
commands = { 
    'main' : 'ls /home', 
    'pipe_to': 'tee -a ' + logfile 
} 

process = sp.Popen(commands['main'], shell=True, stdout=sp.PIPE) 
# explicitly force waits till command terminate, set and return exit status code 
process.wait() 

if process.returncode == STATUS_OK: 
    stdoutdata = process.communicate()[0] 
    # pipe last command output to "tee" command 
    sp.Popen(commands['pipe_to'], stdin=sp.PIPE, shell=1).communicate(stdoutdata) 
else: 
    # do something when command fails 'ls /hom' (in this case) fails 
    pass 

То есть это!
I the last Popen мы вызываем Popen.communicate(), чтобы отправить последний вывод с ls команду tee команда STDIN.

В документе Python есть крошечный учебник под названием Replacing shell pipeline, может быть, вы хотите взглянуть.

Смежные вопросы