Для поддержки широкого спектра вариантов использования класс subprocess.Popen()
и вспомогательные функции принимают большое количество необязательных аргументов. Для большинства типичных случаев использования, многие из этих аргументов могут быть безопасно оставлены со значениями по умолчанию.
Наиболее часто используемые аргументы:
Аргументы args
требуются для всех вызовов и должны быть строкой или последовательностью аргументов программы.
shell=True
.Аргументы stdin
, stdout
и stderr
задают стандартный обработчик входных данных, стандартный вывод и стандартные файл ошибок соответственно. Допустимые значения: subprocess.PIPE
- указывает, что должна быть создана новый поток для дочернего элемента. subprocess.DEVNULL
указывает, что будет использоваться специальный файл os.devnull
. При настройках по умолчанию None
перенаправление не происходит. Дескрипторы файла дочернего процесса будут унаследованы от родителя. Кроме того параметр stderr
может принимать subprocess.STDOUT
, что означает, что данные stderr
из дочернего процесса должны быть записаны в тот же дескриптор файла, что и для stdout
.
import subprocess # вывод команды ls будет выводится в файл `out.log`, а ошибки в `err.log` with open('out.log','w') as out, open('err.log','w') as err: subprocess.Popen(["ls", "/home","-Rla"], \ stdout=out, stderr=err)
Если заданы encoding
или errors
, или text=True
(также известный как universal_newlines
), то файловые объекты stdin
, stdout
и stderr
будут открыты в текстовом режиме с использованием encoding
и errors
, указанных в вызове, или значений по умолчанию для io.TextIOWrapper
.
>>> import subprocess # байтовый режим >>> result = subprocess.run(['ping', '-c', '3', '-n', 'host.host'], \ stderr=subprocess.PIPE) >>> result.stderr # b'ping: host.host: \xd0\x9d\xd0\xb5\ ... \n' # текстовый режим, при указании encoding='utf-8' >>> result = subprocess.run(['ping', '-c', '3', '-n', 'host.host'], \ stderr=subprocess.PIPE, encoding='utf-8') >>> result.stderr # 'ping: host.host: Неизвестное имя или служба\n' # текстовый режим, при указании text=True, аргумент encoding # при декодировании байтов будет использовать кодировку # используемую интерпретатором по умолчанию >>> result = subprocess.run(['ping', '-c', '3', '-n', 'host.host'], \ stderr=subprocess.PIPE, text=True) >>> result.stderr # 'ping: host.host: Неизвестное имя или служба\n'
Для стандартного ввода stdin
символы конца строки '\n'
на входе будут преобразованы в разделитель строк по умолчанию os.linesep
. Для stdout
и stderr
все окончания строк в выводе будут преобразованы в '\n'
. Для получения дополнительной информации смотрите описание класса io.TextIOWrapper
, когда аргумент newline
для его конструктора равен None
.
Если текстовый режим не используется, то stdin
, stdout
и stderr
будут открыты как двоичные потоки. Кодирование или преобразование конца строки не выполняется.
Примечание:
newlines
файловых объектов Popen.stdin
, Popen.stdout
и Popen.stderr
не обновляется методом subprocess.Popen.communicate()
.Если аргумент shell=True
, то указанная команда будет выполнена через оболочку /bin/sh
. Это может быть полезно, если Python используется для расширенного управления потоками, который он предлагает над большинством системных оболочек, при этом все еще необходимо получить удобный доступ к другим функциям оболочки, таким как каналы '|'
, подстановочные wildcard-выражения имени файла *.tpl
, расширение переменных окружения и расширение в домашнюю директорию пользователя символом '~'
. При этом выполняемую команду со всеми ее параметрами необходимо передавать как строку, например cat /var/log/access.log | cut -d" " -f1 | sort | uniq -c
.
>>> import subprocess >>> result = subprocess.Popen(['ls', '-l', '/tmp/*.tpl']) # ls: невозможно получить доступ к '/tmp/*.tpl': Нет такого файла или каталога >>> result = subprocess.run('ls -ls /tmp/*.tpl', shell=True, \ stdout=subprocess.PIPE, encoding='utf-8') >>> result.stdout # '4 -rw------- 1 docs-python docs-python 317 мая 12 09:56 /tmp/tmp-26999MFPH5MgIW157.tpl\n'
Обратите внимание, что сам Python предлагает реализации многих подобных функций оболочки, в частности это glob
, fnmatch
, os.walk()
, os.path.expandvars()
, os.path.expanduser()
и shutil
.
В отличие от некоторых других popen-функций, класс subprocess.Popen()
никогда не будет явно вызывать системную оболочку. Это означает, что все символы, включая метасимволы оболочки, могут безопасно передаваться дочерним процессам. Если оболочка вызывается явно, через shell=True
, то приложение должно гарантировать, что все пробелы и метасимволы указаны в кавычках, чтобы избежать уязвимостей внедрения оболочки.
При использовании shell=True
можно использовать функцию shlex.quote()
для правильного экранирования пробелов и метасимволов оболочки в строках, которые будут использоваться для построения команд оболочки.
>>> import shlex # Эта идиома была бы небезопасна: >>> filename = 'somefile; rm -rf ~' >>> command = f'ls -l {filename}' >>> print(command) # ls -l somefile; rm -rf ~ # quote() позволяет закрыть дыру в безопасности: >>> command = f'ls -l {shlex.quote(filename)}' >>> print(command) # ls -l 'somefile; rm -rf ~'