Подпроцессы. Подпроцессы. Подпроцессы.

Подпроцессы.

Open in new window

Подпроцессы.

Каждыйте раз, когда вы запускаете программу Python из командной строки, например:

python myprogramm.py

Операционная система создает новый процесс, в котором происходит работа вашей программы.

Любая программа оперирует тремя потоками: поток ввода (input), поток вывода (output) и поток ошибок (error).

Обычно input - клавиатура output и error - окно терминала.

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

Для этого можно использовать встроенный модуль subprocess

Сигнатура его вызова следующая:

subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False)

Как видим, при вызове мы можем определить поведение с 3-мя потоками.

Первым параметром мы передаем команду, которую хотим выполнить.

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

Последним параметром мы указываем будет ли наша команда выполнятся в контексте коммандного интерпретатора shell.

Если он установле в True, то Python перед запуском вашей команды запустит интерпретатор shell и в нем уже выполнит команду.

При таком подходе вам станут доступными все команды shell и переменные окружения, что делает запуск не совсем безопасным.

Примеры вызова:

from subprocess import call

subprocess.call(['ls','l'],shell=True)

subprocess.call(['pwd'],shell=True)

Пример уязвимости:

filename = input("What file would you like to display?\n")
What file would you like to display?
on_existent; rm -rf / 
call("cat " + filename, shell=True) # Это может очень плохо закончиться!

Пример перехвата вывода и сохранения в файл.

from subprocess import call
file = open('output.txt','w')
call('ls',stdout=file,shell=True)
print 'done!'

subprocess.check_call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)

Выполняет команду, описанную args. Ожидает завершения команды, а затем завершается, если код возврата 0, или поднимает исключение CalledProcessError, объект которого возвращает код завершения атрибутом returncode.

subprocess.check_output(args, *, input=None, stdin=None, stderr=None, shell=False, universal_newlines=False, timeout=None)

Позволяет забрать вывод команды в строку.

c = subprocess.check_output(['pwd'],shell=True)

Поднимает исключение CalledProcessError, если код возврата ненулевой.

Popen класс.

Служит для создания и управления потоками.

>>>p = args = ['ls']
>>> p = subprocess.Popen(args)
>>> chdir_ex.py  os_ex.py  out_in_file.py  output.txt
p
<subprocess.Popen object at 0x7f5248d8f290>

С помощью этого конструктора мы тоже запускаем команду в новом процессе, не блокируя выполнение вызывающей программы.

Нам возвращается объект и мы можем взаимодействовать с этим объектом в момент выполнения в нем нашей команды.

В отличие от call, Popen не блокирует выполнение вызывающей программы и она продолжает свое выполнение.

Такая работа, при которой одна программа порождает другую не прерываясь, называется асинхронной.

Методы класса Popen.

Popen.poll() - если процесс завершил работу - вернёт код возврата, в ином случае None.

Popen.wait(timeout=None) - ожидает завершения работы процесса и возвращает код возврата. Если в течение timeout процесс не завершился, поднимется исключение TimeoutExpired (которое можно перехватить, после чего сделать ещё раз wait).

Popen.communicate(input=None, timeout=None) - взаимодействовует с процессом: посылает данные, содержащиеся в input в stdin процесса, ожидает завершения работы процесса, возвращает кортеж данных потока вывода и ошибок. При этом в Popen необходимо задать значение PIPE для stdin (если вы хотите посылать в stdin), stdout, stderr (если вы хотите прочитать вывод дочернего процесса).

Если в течение timeout процесс не завершился, поднимется исключение TimeoutExpired (которое можно перехватить, после чего сделать ещё раз communicate, либо убить дочерний процесс).

Popen.send_signal(signal) - посылает сигнал signal.

Popen.terminate() - останавливает дочерний процесс.

Popen.kill() - убивает дочерний процесс.

Other topics