Во всех официально поддерживаемых версиях Python самым простым подходом является использование subprocess.check_output
< / a> функция:
>>> subprocess.check_output(['ls', '-l'])
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
check_output
запускает единственную программу, которая принимает в качестве входных данных только аргументы. 1 Она возвращает результат точно так, как напечатано для stdout
. Если вам нужно записать ввод в stdin
, переходите к разделам run
или Popen
. Если вы хотите выполнять сложные команды оболочки, см. Примечание о shell=True
в конце этого ответа.
Функция check_output
работает во всех официально поддерживаемых версиях Python. Но для более поздних версий доступен более гибкий подход.
Современные версии Python (3.5 и выше): run
Если вы используете Python 3.5+ и вам не нужна обратная совместимость, новая run
функция рекомендована официальной документацией для большинства задач. Он предоставляет общий высокоуровневый API для модуля subprocess
. Чтобы захватить вывод программы, передайте флаг subprocess.PIPE
аргументу ключевого слова stdout
. Затем обратитесь к атрибуту stdout
возвращенного объекта CompletedProcess
:
>>> import subprocess
>>> result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
>>> result.stdout
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
Возвращаемое значение - объект bytes
, поэтому, если вам нужна правильная строка, вам нужно decode
ее. Предполагая, что вызываемый процесс возвращает строку в кодировке UTF-8:
>>> result.stdout.decode('utf-8')
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
При желании все это можно сжать до однострочного:
>>> subprocess.run(['ls', '-l'], stdout=subprocess.PIPE).stdout.decode('utf-8')
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
Если вы хотите передать ввод в stdin
процесса, вы можете передать объект bytes
в аргумент ключевого слова input
:
>>> cmd = ['awk', 'length($0) > 5']
>>> ip = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=ip)
>>> result.stdout.decode('utf-8')
'foofoo\n'
Вы можете фиксировать ошибки, передавая stderr=subprocess.PIPE
(захват в result.stderr
) или stderr=subprocess.STDOUT
(захват в result.stdout
вместе с обычным выводом). Если вы хотите, чтобы run
генерировал исключение, когда процесс возвращает ненулевой код выхода, вы можете передать check=True
. (Или вы можете проверить атрибут returncode
в result
выше.) Если безопасность не является проблемой, вы также можете запускать более сложные команды оболочки, передавая shell=True
, как описано в конце этого ответа.
Более поздние версии Python оптимизируют вышесказанное. В Python 3.7+ приведенный выше однострочный текст можно записать так:
>>> subprocess.run(['ls', '-l'], capture_output=True, text=True).stdout
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'
Использование run
таким способом добавляет немного сложности по сравнению со старым способом работы. Но теперь вы можете делать почти все, что вам нужно, только с помощью функции run
.
Старые версии Python (3-3.4): подробнее о check_output
Если вы используете старую версию Python или вам нужна умеренная обратная совместимость, вы можете использовать функцию check_output
, как кратко описано выше. Он доступен начиная с Python 2.7.
subprocess.check_output(*popenargs, **kwargs)
Он принимает те же аргументы, что и Popen
(см. Ниже), и возвращает строку, содержащую вывод программы. В начале этого ответа есть более подробный пример использования. В Python 3.5+ check_output
эквивалентно выполнению run
с check=True
и stdout=PIPE
и возврату только атрибута stdout
.
Вы можете передать stderr=subprocess.STDOUT
, чтобы гарантировать включение сообщений об ошибках в возвращаемый результат. Когда безопасность не важна, вы также можете запускать более сложные команды оболочки, передав shell=True
, как описано в конце этого ответа.
Если вам нужно передать по конвейеру от stderr
или передать ввод процессу, check_output
не справится с этой задачей. В этом случае см. Popen
примеры ниже.
Сложные приложения и устаревшие версии Python (2.6 и ниже): Popen
Если вам нужна глубокая обратная совместимость или если вам нужна более сложная функциональность, чем предоставляют check_output
или run
, вам придется работать напрямую с Popen
объектами, которые инкапсулируют низкоуровневый API для подпроцессов.
Конструктор Popen
принимает либо одну команду без аргументов, либо список, содержащий команду в качестве первого элемента, за которым следует любое количество аргументов, каждый как отдельный элемент в список. shlex.split
может помочь преобразовать строки в списки с соответствующим форматом. Popen
объекты также принимают множество различных аргументов для управления вводом-выводом процесса. и низкоуровневая конфигурация.
Для отправки ввода и вывода вывода почти всегда предпочтительным методом является communicate
. Как в:
output = subprocess.Popen(["mycmd", "myarg"],
stdout=subprocess.PIPE).communicate()[0]
Or
>>> import subprocess
>>> p = subprocess.Popen(['ls', '-a'], stdout=subprocess.PIPE,
... stderr=subprocess.PIPE)
>>> out, err = p.communicate()
>>> print out
.
..
foo
Если вы установите stdin=PIPE
, communicate
также позволяет передавать данные процессу через stdin
:
>>> cmd = ['awk', 'length($0) > 5']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
... stderr=subprocess.PIPE,
... stdin=subprocess.PIPE)
>>> out, err = p.communicate('foo\nfoofoo\n')
>>> print out
foofoo
Обратите внимание на ответ Аарона Холла, в котором указано, что в некоторых системах вам может потребоваться установить stdout
, stderr
и stdin
все на PIPE
(или DEVNULL
), чтобы communicate
вообще заработал.
В некоторых редких случаях может потребоваться сложный захват вывода в реальном времени. Ответ Vartec предлагает путь вперед, но методы, отличные от communicate
, подвержены тупиковым ситуациям, если их не использовать осторожно.
Как и в случае со всеми вышеупомянутыми функциями, когда безопасность не является проблемой, вы можете запускать более сложные команды оболочки, передавая shell=True
.
Примечания
1. Запуск команд оболочки: аргумент shell=True
Обычно каждый вызов конструктора run
, check_output
или Popen
выполняет отдельную программу. Это означает отсутствие причудливых каналов в стиле bash. Если вы хотите запускать сложные команды оболочки, вы можете передать shell=True
, который поддерживают все три функции. Например:
>>> subprocess.check_output('cat books/* | wc', shell=True, text=True)
' 1299377 17005208 101299376\n'
Однако при этом возникают проблемы безопасности. Если вы делаете что-то большее, чем сценарии освещения, вам может быть лучше вызывать каждый процесс отдельно и передавать вывод каждого в качестве ввода следующему через
run(cmd, [stdout=etc...], input=other_output)
Or
Popen(cmd, [stdout=etc...]).communicate(other_output)
Соблазн напрямую соединить трубы велик; сопротивляться этому. В противном случае вы, скорее всего, столкнетесь с тупиками или вам придется делать такие хакерские вещи, как this.
person
senderle
schedule
21.01.2011