Сообщить об ошибке.

Часто используемые аргументы модуля subprocess

Для поддержки широкого спектра вариантов использования класс 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 ~'