C:\...\PP4E\System> python
>>> import os
>>> os.system('dir /B')
helloshell.py
more.py
more.pyc
spam.txt
__init__.py
0
>>> os.system('type helloshell.py')
# a Python program print(‘The Meaning of Life’)
0 >>> os.system('type hellshell.py')
The system cannot find the file specified.
1
Нули, которые выводятся по окончании выполнения первых двух команд, являются значениями, возвращаемыми самой функцией system. Функцию system можно использовать для выполнения любой командной строки, которую допускается ввести в ответ на приглашение оболочки (здесь приглашением является C:\...\PP4E\System>). Выводимые командой данные обычно попадают в стандартный поток вывода сеанса Python или программы.
Обмен данными с командами оболочки
Но что если в сценарии потребуется перехватить данные, выводимые командой? Функция os.system просто запускает команду оболочки, тогда как функция os.popen дополнительно соединяется со стандартными потоками ввода-вывода команды, - обратно возвращается объект, подобный файлу, по умолчанию соединенный с выводом команды (если передать функции popen флаг режима w, то вместо этого произойдет подключение к потоку ввода команды). Используя этот объект для чтения данных, выводимых командой, запущенной с помощью popen, можно перехватывать текст, в обычных условиях появляющийся в окне консоли, где вводится команда:
>>> open('helloshell.py').read()
"# a Python program\nprint(‘The Meaning of Life’)\n”
>>> text = os.popen('type helloshell.py').read()
>>> text
"# a Python program\nprint(‘The Meaning of Life’)\n”
>>> listing = os.popen('dir /B').readlines()
>>> listing
[‘helloshell.py\n’, ‘more.py\n’, ‘more.pyc\n’, ‘spam.txt\n’, ‘__init__.py\n’]
Здесь мы получаем содержимое файла сначала обычным способом (средствами Python для работы с файлами), а затем - как вывод команды оболочки type. Чтение вывода команды dir позволяет получить список файлов в каталоге, который затем можно обработать в цикле. В главе 4 будут представлены другие способы получения такого списка, и там же мы познакомимся с итераторами файлов, которые в большинстве программ делают ненужным вызов функции readlines, показанный в примере выше, за исключением отображения списка в интерактивной оболочке, как в данном случае (дополнительная информация по этой теме приводится также во врезке «subprocess, os.popen и итераторы» ниже).
До сих пор мы выполняли простые команды DOS, но поскольку эти функции могут запускать любые допустимые команды, с их помощью можно также запускать другие сценарии Python. Предположим, что каталог с выполняемым файлом интерпретатора Python в вашей системе находится в пути поиска файлов (чтобы можно было использовать короткую команду «python» вместо «C:\Python31\python»):
>>> os.system('python helloshell.py') # запустит программу на языке Python The Meaning of Life 0
>>> output = os.popen('python helloshell.py').read()
>>> output
‘The Meaning of Life\n’
Во всех этих примерах командные строки, передаваемые функциям system и popen, жестко «зашиты» непосредственно в программный код, но нет никаких причин, по которым программы на языке Python не могли бы создавать такие строки на этапе выполнения с помощью обычных строковых операций (+, % и других). Учитывая, что команды могут конструироваться и выполняться динамически, функции system и popen превращают сценарии на языке Python в гибкие и переносимые средства запуска и управления другими программами. Например, тестовый «управляющий» сценарий на языке Python можно использовать для запуска программ, написанных на любых языках программирования (например, C++, Java, Python), и анализа их вывода. Такой сценарий будет рассмотрен в главе 6. В следующей главе мы снова вернемся к функции os.popen, где будем рассматривать ее в соединении с проблемой перенаправления потоков ввода-вывода - как будет показано там, механизм перенаправления также может использоваться для передачи ввода в программы.
Альтернатива на основе модуля subprocess
Как уже говорилось, в последних версиях Python появился модуль subprocess, позволяющий добиться того же эффекта, что и функции os.system и os.popen. Вообще говоря, для этого придется написать дополнительный программный код, но этот модуль обеспечивает более полный контроль над подключением и использованием потоков ввода-вывода. Это особенно полезно для реализации сложных схем связывания потоков ввода-вывода.