Как уже говорилось, в последних версиях Python появился модуль subprocess, позволяющий добиться того же эффекта, что и функции os.system и os.popen. Вообще говоря, для этого придется написать дополнительный программный код, но этот модуль обеспечивает более полный контроль над подключением и использованием потоков ввода- вывода. Это особенно полезно для реализации сложных схем связывания потоков ввода-вывода.
Например, чтобы запустить простую команду оболочки, как мы делали это с помощью функции os.system выше, можно воспользоваться функцией call из нового модуля, которая действует похожим образом (чтобы запустить такую команду, как type, встроенную в оболочку Windows, требуется соблюсти дополнительные условия, хотя для запуска обычных выполняемых файлов, таких как python, этого не требуется):
> >> import subprocess
> >> subprocess.call(‘python helloshell.py’) # напоминает os.system() The Meaning of Life
0
> >> subprocess.call(‘cmd /C “type helloshell.py”’) # встроенная команда
> a Python program
print(‘The Meaning of Life’)
0
> >> subprocess.call(‘type helloshell.py’, shell=True) # альтернативный способ
> a Python program # для встроенных команд
print(‘The Meaning of Life’)
0
Обратите внимание на аргумент shell=True в последнем вызове. Это платформозависимая особенность:
• Чтобы запустить встроенную команду оболочки в Windows, инструментам модуля subprocess, таким как call и Popen (об этой функции будет рассказываться ниже), необходимо передавать аргумент shell=True. Команды Windows, такие как type, требуют соблюдения дополнительных условий, но для запуска обычных выполняемых файлов, таких как python, этого не требуется.
• В Unix-подобных платформах, когда аргумент shell принимает значение False (по умолчанию), команда запускается непосредственно вызовом функции os.execvp, с которой мы встретимся в главе 5. Если в этом аргументе передать True, команда будет выполнена с помощью оболочки, при этом вы можете указать используемую оболочку в дополнительном аргументе.
Подробнее о некоторых из этих особенностей мы поговорим ниже, а пока достаточно будет запомнить, что в Unix-подобных системах вам может потребоваться передавать аргумент shell=True в некоторых примерах в этом разделе и в книге, если они предполагают использование таких особенностей оболочки, как путь поиска программ. Поскольку я запускаю примеры в Windows, этот аргумент я часто буду опускать.
Помимо имитации функции os.system, мы точно так же можем использовать этот модуль для имитации функции os.popen, чтобы запускать команды оболочки и получать ее вывод в нашем сценарии:
>>> pipe = subprocess.Popen(‘python helloshell.py’, stdout=subprocess.PIPE)
>>> pipe.communicate()
(b’The Meaning of Life\r\n’, None)
>>> pipe.returncode
0
Здесь мы связали поток стандартного вывода команды оболочки с каналом и вызвали метод communicate, ожидающий завершения команды и принимающий текст, который она выводит в стандартный поток вывода и в стандартный поток ошибок. Код завершения команды доступен в виде атрибута, после того как она будет выполнена. Точно так же мы могли бы использовать отдельную функцию чтения потока стандартного вывода команды и отдельную функцию ожидания ее завершения (которая возвращает код завершения):
>>> pipe = subprocess.Popen(‘python helloshell.py’, stdout=subprocess.PIPE)
>>> pipe.stdout.read()
b’The Meaning of Life\r\n’
>>> pipe.wait()
0
Фактически существует возможность прямой замены вызова os.popen объектом subprocess.Popen:
> >> from subprocess import Popen, PIPE
> >> Popen(‘python helloshell.py’, stdout=PIPE).communicate()[0] b’The Meaning of Life\r\n’
>>>
> >> import os
> >> os.popen(‘python helloshell.py’).read()
‘The Meaning of Life\n’
Как видите, реализация относительно простых случаев с помощью модуля subprocess требует дополнительной работы. Но ситуация меняется в лучшую сторону, когда возникает необходимость гибкого управления потоками ввода-вывода. Фактически, благодаря возможности обрабатывать стандартные потоки вывода и ошибок команды похожими способами, модуль subprocess в Python 3.X заменил оригинальные функции os.popen2, os.popen3 и os.popen4, имевшиеся в Python 2.X. Теперь эти функции являются лишь частными случаями использования интерфейса объектов модуля subprocess. Поскольку в более сложных случаях использования этого модуля предполагается взаимодействие со стандартными потоками ввода-вывода, мы отложим дальнейшее обсуждение этого модуля, пока не познакомимся с механизмом перенаправления потоков в следующей главе.
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011