Нужен лучший способ выполнения консольных команд из python и записи результатов - PullRequest
4 голосов
/ 18 февраля 2009

У меня есть скрипт на python, который должен выполнять несколько утилит командной строки. Вывод stdout иногда используется для дальнейшей обработки. Во всех случаях я хочу зарегистрировать результаты и вызвать исключение, если обнаружена ошибка. Для этого я использую следующую функцию:

def execute(cmd, logsink):
    logsink.log("executing: %s\n" % cmd)
    popen_obj = subprocess.Popen(\
          cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (stdout, stderr) = popen_obj.communicate()
    returncode = popen_obj.returncode
    if (returncode <> 0):
       logsink.log("   RETURN CODE: %s\n" % str(returncode))
    if (len(stdout.strip()) > 0):
       logsink.log("   STDOUT:\n%s\n" % stdout)
    if (len(stderr.strip()) > 0):
       logsink.log("   STDERR:\n%s\n" % stderr)
    if (returncode <> 0):
       raise Exception, "execute failed with error output:\n%s" % stderr
    return stdout

"logsink" может быть любым объектом python с методом log. Обычно я использую это для пересылки данных регистрации в определенный файл, или вывод их на консоль, или в оба, или что-то еще ...

Это работает довольно хорошо, за исключением трех проблем, когда мне нужно более детальное управление, чем обеспечивает метод connect ():

  1. Вывод stdout и stderr может чередоваться на консоль, но функция журналов выше их отдельно. Это может усложнить интерпретацию журнал. Как мне войти в stdout и stderr чередование строк в том же порядке как они были выведены?
  2. Вышеуказанная функция будет регистрировать только вывод команды, как только команда завершено. Это усложняет диагностику проблем, когда команды застревают в бесконечном цикле или занимают очень много времени по какой-либо другой причине. Как получить журнал в режиме реального времени, пока команда еще выполняется?
  3. Если журналы большие, он может получить трудно интерпретировать, какая команда генерируется какой выход. Есть ли способ префикс каждой строки с что-то (например, первое слово строка cmd, за которой следует:).

Ответы [ 4 ]

5 голосов
/ 18 февраля 2009

Вы можете перенаправить в файл, если вы просто хотите вывод в файл для последующей оценки.

Вы уже определили stdout / stderr процессов, которые вы выполняете методами stdout = / stderr =.

В вашем примере кода вы просто перенаправляете в скрипты текущие назначения out / err.

subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)

sys.stdout и sys.stderr - это просто файловые объекты. Как указано в документации по sys.stdout , «любой объект приемлем, если у него есть метод write (), который принимает строковый аргумент."

f = open('cmd_fileoutput.txt', 'w')
subprocess.Popen(cmd, shell=True, stdout=f, stderr=f)

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

Если вы хотите, чтобы как вывод на консоль, так и вывод на файл могли создавать класс для управления выводом.

Общее перенаправление:

# Redirecting stdout and stderr to a file
f = open('log.txt', 'w')
sys.stdout = f
sys.stderr = f

Создание класса перенаправления:

# redirecting to both
class OutputManager:
    def __init__(self, filename, console):
        self.f = open(filename, 'w')
        self.con = console

    def write(self, data):
        self.con.write(data)
        self.f.write(data)

new_stdout = OutputManager("log.txt", sys.stdout)

Чередование зависит от буферизации, поэтому вы можете получить или не получить ожидаемый результат. (Возможно, вы можете отключить или уменьшить используемую буферизацию, но я не помню, как сейчас)

2 голосов
/ 18 февраля 2009

Вы можете посмотреть в pexpect (http://www.noah.org/wiki/Pexpect)

Это решает 1) и 2) из ​​коробки, префикс вывода может быть немного сложнее.

1 голос
/ 23 июня 2010

Это ни в коем случае не полный или исчерпывающий ответ, но, возможно, вам стоит заглянуть в модуль Fabric.

http://docs.fabfile.org/0.9.1/

Упрощает параллельное выполнение команд оболочки и обработку ошибок.

1 голос
/ 15 марта 2010

Еще один вариант:

def run_test(test_cmd):
    with tempfile.TemporaryFile() as cmd_out:
        proc = subprocess.Popen(test_cmd, stdout=cmd_out, stderr=cmd_out)
        proc.wait()
        cmd_out.seek(0)
        output = "".join(cmd_out.readlines())
    return (proc.returncode, output)

Это будет чередовать stdout и stderr по желанию в реальном файле, который вам удобно открыть.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...