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