Стандартный модуль subprocess позволяет вызывать процессы из Python и взаимодействовать с ними: отправлять данные на вход (stdin) и получать информацию на выходе (stdout).
Также можно дождаться завершения процесса или завершить его преждевременно и получить возвращаемое значение.
Это идеальный и рекомендуемый метод для выполнения команд операционной системы или запуска программ (вместо традиционного os.system()) и опционального взаимодействия с ними.
Самый простой способ выполнить команду или вызвать процесс – это функция call() (с Python 2.4 по 3.4) или run() (3.5+).
Например, следующий код выполняет команду, которая перезагружает систему.
Python 3.5+
>>> import subprocess
>>> subprocess.run(["shutdown", "-r"])
Code language: CSS (css)
Python 2.4-3.4
>>> import subprocess
>>> subprocess.call(["shutdown", "-r"])
Code language: CSS (css)
При вызове команды, содержащей пробелы (особенно в дистрибутивах Linux), рекомендуется передавать список вместо строки, чтобы избежать неправильной интерпретации.
Python 3.5+
>>> subprocess.run("shutdown -r")
Traceback (most recent call last):
...
OSError: [Errno 2] No such file or directory
Code language: CSS (css)
Python 2.4-3.4
>>> subprocess.call("shutdown -r")
Traceback (most recent call last):
...
OSError: [Errno 2] No such file or directory
Code language: CSS (css)
Обе функции не возвращаются, пока вызванная программа не завершится. call() вернет возвращаемое значение выполненной команды или программы в виде целого числа. run() вернет экземпляр CompletedProcess, который содержит атрибут returncode.
Python 3.5+
>>> p = subprocess.run(["python", "--version"])
Python 3.5.1
>>> p.returncode
0
Code language: JavaScript (javascript)
Python 2.4-3.4
>>> ret = subprocess.call(["python", "--version"])
Python 2.7.13
>>> ret
0
Code language: JavaScript (javascript)
(Обычно 0 означает, что программа была выполнена правильно).
Для использования команд терминала (таких как clear или cls для очистки консоли, cd для перемещения по дереву каталогов и т.д.) необходимо указать параметр shell=True.
Python 3.5+
>>> subprocess.run("cls", shell=True)
Code language: PHP (php)
Python 2.4-3.4
>>> subprocess.call("cls", shell=True)
Code language: PHP (php)
Важно отметить, что использование shell=True является потенциальной уязвимостью, если команда выполняется пользователем (аналогично методу инъекции SQL-кода в приложениях, взаимодействующих с базами данных).
Теперь, чтобы сохранить вывод команды в виде строки Python, мы должны указать параметры stdout и stderr. Например:
Python 3.5+
>>> p = subprocess.run("ver", stdout=subprocess.PIPE, shell=True)
>>> p.stdout
b'\r\nMicrosoft Windows [Versi\xa2n 6.2.9200]\r\n'
Code language: PHP (php)
Python 2.4-3.4
>>> p = subprocess.Popen("ver", stdout=subprocess.PIPE, shell=True)
>>> stdout = p.communicate()[0]
>>> stdout
'\r\nMicrosoft Windows [Versi\xa2n 6.2.9200]\r\n'
Code language: PHP (php)
Команда Windows ver отправляет версию системы в stdout. Мы можем получить к нему доступ через атрибут stdout (3.5+) или метод communicate() (2.4-3.4)
Обратите внимание, что в Python 3 результат является экземпляром типа bytes, в Python 2 – типа str.
Для доступа к потенциальным ошибкам, отправленным в stderr, процесс аналогичен:
Python 3.5+
>>> p = subprocess.run(["python", "-m", "inexistente"], stderr=subprocess.PIPE)
>>> p.stderr
b'C:\\python35\\python.exe: No module named inexistente\r\n'
Code language: JavaScript (javascript)
Python 2.4-3.4
>>> p = subprocess.Popen(["python", "-m", "inexistente"],
stderr=subprocess.PIPE)
>>> stderr = p.communicate()[1]
>>> stderr
'C:\\Python27\\python.exe: No module named inexistente\r\n'
Code language: JavaScript (javascript)
И stdout, и stderr опционально принимают файлы для хранения данных на диске:
Python 3.5+
with open("errores.log", "w") as f:
p = subprocess.run(["python", "-m", "inexistente"], stderr=f)
Code language: JavaScript (javascript)
Python 2.4-3.4
with open("errores.log", "w") as f:
p = subprocess.Popen(["python", "-m", "inexistente"], stderr=f)
Code language: JavaScript (javascript)
Также можно перенаправить все, что отправлено в stderr, в stdout:
Python 3.5+
>>> p = subprocess.run(["python", "-m", "inexistente"], stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
>>> p.stdout
b'C:\\python35\\python.exe: No module named inexistente\r\n'
Code language: JavaScript (javascript)
Python 2.4-3.4
>>> p = subprocess.Popen(["python", "-m", "inexistente"],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT)
>>> stdout = p.communicate()[0]
>>> stdout
'C:\\Python27\\python.exe: No module named inexistente\r\n'
Code language: JavaScript (javascript)
Чтобы отправить данные на вход (stdin), давайте сначала рассмотрим следующий пример кода:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
try:
# Python 2.
name = raw_input("Имя: ")
except NameError:
# Python 3.
name = input("Имя: ")
print("Привет " + name)
Code language: PHP (php)
Этот небольшой код, назовем его program.py, предлагает пользователю ввести свое имя, а затем выводит на экран приветствие.
Через подпроцесс мы можем вызвать его, программно ввести имя и получить приветствие в виде строки Python.
Python 3.5+
p = subprocess.run(["python", "program.py"], input=b"Иван",
stdout=subprocess.PIPE)
print(p.stdout)
Code language: PHP (php)
Python 2.4-3.4
p = subprocess.Popen(["python", "program.py"], stdin=subprocess.PIPE,
stdout=subprocess.PIPE)
stdout = p.communicate(input="Иван")[0]
print stdout
Code language: PHP (php)
Имя передается через входной параметр (из функций run() или communicate() в зависимости от версии) на вход (stdin), а приветствие получается путем обращения к содержимому выхода (stdout).
Другие допустимые аргументы для popen(), call() и run() включают cwd (текущий рабочий каталог), который указывает место, где будет выполняться команда или программа.
Это обычно полезно, когда процесс обращается к файлам по относительному пути.
Python 3.5+
>>> subprocess.run("ls", cwd="Desktop")
Code language: JavaScript (javascript)
Python 2.4-3.4
>>> subprocess.call("ls", cwd="Desktop")
Code language: JavaScript (javascript)
Экземпляры Popen() включают методы terminate() и kill(), чтобы завершить или убить процесс, соответственно.
Дистрибутивы Linux различают сигналы SIGTERM и SIGKILL. В Windows нет никакой разницы между этими двумя функциями.
# Преждевременное прекращение процесса.
p = subprocess.Popen(["python", "--version"])
p.terminate()
Code language: PHP (php)
Другие методы включают p.wait() для блокировки выполнения до тех пор, пока программа не завершится (это происходит по умолчанию при вызове call() или run()) и атрибут p.pid, который хранит идентификатор созданного процесса.