перенаправление вывода оболочки с использованием подпроцесса - PullRequest
1 голос
/ 03 июля 2011

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

Я написал помощникфункция для вызова функций оболочки:

import subprocess
import shlex
import sys

def shell(cmdline, interactive=True):
    args = shlex.split(cmdline.encode("ascii"))
    proc = subprocess.Popen(args, stdout=subprocess.PIPE,
        stderr=subprocess.PIPE)
    val = proc.communicate()
    if interactive is True:
        if proc.returncode:
            print "returncode " + str(proc.returncode)
            print val[1]
            sys.exit(1)
        else:
            print val[0]
    else:
        if proc.returncode:
            print ""
            # send email with val[0] + val[1]

if __name__ == "__main__":
    # example of command that produces non-zero returncode
    shell("ls -z")

У меня двойная проблема.

1) В интерактивном режиме, когда выполнение команды оболочки занимает некоторое время (например, несколькоминут), я ничего не вижу до тех пор, пока команда не будет полностью выполнена, так как Communication () буферизирует вывод.Есть ли способ отобразить вывод, как он поступает, и избежать буферизации?Мне также нужен способ проверки кода возврата, поэтому я использую функцию connect ().

2) Некоторые команды оболочки, которые я вызываю, могут выдавать много выходных данных (например, 2 МБ).Документация для connect () гласит: «Не используйте этот метод, если размер данных большой или неограниченный».Кто-нибудь знает, насколько велик "большой"?

1 Ответ

2 голосов
/ 03 июля 2011

1) Когда вы используете общаться , вы фиксируете выходные данные подпроцесса, поэтому на стандартный вывод ничего не отправляется.Единственная причина, по которой вы видите выходные данные после завершения подпроцесса, заключается в том, что вы распечатываете его сами.

Поскольку вы хотите либо видеть его во время работы, а не захватывать его, либо захватывать все и делать что-то с ним только вВ конце концов, вы можете изменить способ работы в интерактивном режиме, оставив stdout и stderr до Нет .Это заставляет подпроцесс использовать те же потоки, что и ваша программа.Вам также придется заменить вызов на общаться на вызов wait :

if interactive is True:
    proc = subprocess.Popen(args)
    proc.wait()
    if proc.returncode:
        print "returncode " + str(proc.returncode)
        sys.exit(1)
else:
    proc = subprocess.Popen(args, stdout=subprocess.PIPE,
        stderr=subprocess.PIPE)
    val = proc.communicate()
    if proc.returncode:
        print ""
        # send email with val[0] + val[1]

2) Слишком большой "слишком велик для хранения в памяти"«Так что все зависит от множества факторов.Если в вашей ситуации хорошо временно хранить 2 МБ данных в памяти, беспокоиться не о чем.

...