перенаправление вывода оболочки с использованием подпроцесса

1

У меня есть скрипт 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) В интерактивном режиме, когда команда оболочки занимает некоторое время, чтобы закончить (например, несколько минут), я ничего не вижу, пока команда не будет полностью выполнена, поскольку вывод буферов обмена(). Есть ли способ отображать вывод, когда он входит, и избегать буферизации? Мне также нужен способ проверить код возврата, поэтому я использую функцию связи().

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

Теги:
subprocess

1 ответ

2
Лучший ответ

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

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

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 МБ данных в памяти в вашей ситуации, тогда вам не о чем беспокоиться.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню