Ответ на этот вопрос зависит от версии Python, которую вы используете. Самый простой подход - использовать subprocess.check_output
функцию:
>>> 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 - прежнему широко используется (2.7+). 2 Но для более поздних версий это уже не рекомендуемый подход.
Современные версии 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']
>>> input = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=input)
>>> result.stdout.decode('utf-8')
'foofoo\n'
Вы можете фиксировать ошибки, передавая stderr=subprocess.PIPE
(capture to result.stderr
) или stderr=subprocess.STDOUT
(capture to result.stdout
вместе с обычным выводом). Когда безопасность не имеет значения, вы также можете запускать более сложные команды оболочки, передавая, shell=True
как описано в примечаниях ниже.
Это добавляет немного сложности по сравнению со старым способом ведения дел. Но я думаю, что это того стоит: теперь вы можете делать практически все, что вам нужно, с помощью run
одной функции.
Старые версии Python (2.7-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
к тому , чтобы сообщения об ошибках включены в возвращенном выходе - но в некоторых версиях Python перехода stderr=subprocess.PIPE
к check_output
может привести к тупикам . Когда безопасность не имеет значения, вы также можете запускать более сложные команды оболочки, передавая, shell=True
как описано в примечаниях ниже.
Если вам нужно stderr
передать или передать входные данные процессу, check_output
не справится с задачей. Смотрите Popen
примеры ниже в этом случае.
Сложные приложения и устаревшие версии Python (2.6 и ниже): Popen
Если вам нужна глубокая обратная совместимость, или если вам нужна более сложная функциональность, чем check_output
предоставляет, вам придется работать непосредственно с Popen
объектами, которые инкапсулируют низкоуровневый API для подпроцессов.
Popen
Конструктор принимает либо одну команду без аргументов, или список , содержащий команду в качестве первого элемента, за которым следует любое количество аргументов, каждый из которых в качестве отдельного элемента в списке. shlex.split
может помочь разобрать строки в соответственно отформатированных списках. Popen
объекты также принимают множество различных аргументов для управления процессами ввода-вывода и низкоуровневой конфигурации.
Для отправки ввода и захвата вывода, communicate
почти всегда предпочтительный метод. Как в:
output = subprocess.Popen(["mycmd", "myarg"],
stdout=subprocess.PIPE).communicate()[0]
Или
>>> 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
чтобы работать на всех.
В некоторых редких случаях вам может потребоваться сложный захват выходных данных в режиме реального времени. Ответ Вартека предлагает дальнейший путь, но методы, отличные от communicate
тупиковых, если их не использовать осторожно.
Как и во всех вышеперечисленных функциях, когда безопасность не имеет значения, вы можете передавать более сложные команды оболочки, передавая их shell=True
.
Ноты
1. Запуск команд оболочки: shell=True
аргумент
Как правило, каждый вызов run
, check_output
или Popen
конструктор выполняет одну программу . Это означает, что нет причудливых трубок в стиле Баш. Если вы хотите запускать сложные команды оболочки, вы можете передать shell=True
, что поддерживают все три функции.
Однако при этом возникают проблемы с безопасностью . Если вы делаете что-то большее, чем простой сценарий, вам лучше вызывать каждый процесс отдельно и передавать выходные данные каждого из них как входные данные следующему через
run(cmd, [stdout=etc...], input=other_output)
Или
Popen(cmd, [stdout=etc...]).communicate(other_output)
Искушение напрямую соединить трубы сильно; сопротивляться этому. В противном случае, вы , вероятно , увидеть тупики или должны сделать Hacky таких вещей , как это .
2. Юникод соображения
check_output
возвращает строку в Python 2, но bytes
объект в Python 3. Стоит потратить некоторое время на изучение юникода, если вы этого еще не сделали.