Больше не нужно искать работу мечты — присоединяйтесь к команде Клауда Подробнее

Как запускать внешние процессы, используя Python

Команда Timeweb Cloud
Команда Timeweb Cloud
Наши инженеры, технические писатели, редакторы и маркетологи
24 марта 2022 г.
4394
7 минут чтения
Средний рейтинг статьи: 5

Современные облачные сервисы, например, timeweb.cloud, стали сегодня обыденностью. Удалённый доступ и удалённое управление – основа современного цифрового мира. В нашей сегодняшней статье мы расскажем вам, как запускать внешние процессы при помощи различных модулей в Python 3.

Как Запускать Внешние Процессы, Используя Python (1)

Для запуска внешних программ из Python, а также получения их ввода или вывода используется встроенный модуль subprocess. Данный модуль позволяет запускать и контролировать выполнение различных программ, которые доступны на компьютере.

Чтобы запустить программу с помощью модуля subprocess можно использовать несколько функций: subprocess.run (пришла на замену функции subprocess.call() в версии Python 3.5) и subprocess.Popen.

Синтаксис subprocess.run

subprocess.run(args, *, stdin, input, stdout,  stderr,
               capture_output, shell, cwd, timeout,
          check, encoding, errors, text, env,
           universal_newlines)

 Аргумент args – обязательный, через него передается запускаемая программа с аргументами.

Параметры stdin, input, stdout и stderr отвечают за потоки данных, которые передаются в процесс или выходят из него. Здесь stdout — поток вывода (результат работы), stderr — поток ошибок, которые возникли при выполнении. По умолчанию их значения — None.

capture_output — по умолчанию False, отвечает за захват результата работы процесса (вывода).

Параметр shell отвечает за способ передачи в процесс программы и ее аргументов — если они представлены как одна строка, следует указать True. По умолчанию False.

cwd — используется, если требуется указать абсолютный путь к каталогу с запускаемой программой.

timeout — время в секундах, по истечении которого процесс завершится. При этом возникает исключение.

check — если имеет значение True, то вызывает исключение, если во время выполнения возникли ошибки. По умолчанию False.

encoding — отвечает за декодирование вывода.

errors — если указан, то ошибки кодировки будут вызывать исключение.

text, universal_newlines — текстовые режимы для потоков ввода, вывода и ошибок. По умолчанию false.

env — переменные среды для нового процесса.

Функция возвращает объект CompletedProcess, содержащий результаты работы. С помощью специальных атрибутов можно получить из этого объекта переданные в функцию аргументы, код результата выполнения, вывод или возникшие ошибки. Работая с этой функцией, необходимо аккуратно работать с кодом из ненадёжных источников, потому что она может выполнять всё подряд, особенно в случае запуска от имени администратора.

Перед тем как рассматривать примеры, импортируем необходимые модули:

from subprocess import run, Popen, PIPE
from sys import executable
python import local file

Значение executable в Python — это абсолютный путь к исполняемому файлу интерпретатора Python. Оно потребуется для запуска кода.

Рассмотрим простой пример применения CompletedProcess.

run("echo 'Subprocesses are cool!", shell=True)

Вывод:

Subprocesses are cool!

Результатом работы будет объект:

CompletedProcess(args="echo 'Subprocesses are cool!", returncode=0)

Здесь мы видим переданные нами аргументы и статус выполнения (returncode). Когда статус выполнения равен нулю, это означает, что выполнение завершено успешно.

Рассмотрим сценарий сложнее. В предыдущем примере мы просто запустили внешний процесс и получили ответ, что он успешно выполнен. Но что если мы хотим получить не только статус выполнения, но и какие-то данные вывода? Для этого нам необходимо установить параметр capture_output = True:

run('ping localhost', shell = True, capture_output = True, encoding='cp866')

В этом примере мы отправляем запрос на localhost для проверки соединения. Параметр encoding указывает, что нам нужно декодировать результат, иначе мы получим его как байтовую строку.

Чтобы получить вывод программы и ошибки, выполним:

print("stdout:", result.stdout)
print("stderr:", result.stderr)

stdout:
Обмен пакетами с DESKTOP-*** [::1] с 32 байтами данных:
Ответ от ::1: время<1мс
Ответ от ::1: время<1мс
Ответ от ::1: время<1мс
Ответ от ::1: время<1мс

stderr:

В случае, если во время выполнения возникла какая-то ошибка, подпроцесс вернет ее в result.stderr. В данном случае ошибок не возникло.

Обработка исключений

Выполним следующий код:

run([executable, "-c", "raise ValueError('It seems there is a mistake!')"], capture_output=True, encoding='cp866')

Элемент -c – это опция командной строки python, позволяющая передавать на ввод целую программу.

Он сработает без проблем, однако если мы захотим вывести stdout, то увидим, что он пустой (в отличие от stderr).

stdout:
stderr: Traceback (most recent call last):
File "<string>", line 1, in <module>
ValueError: It seems there is a mistake!

Если вызвать метод check_returncode, то мы увидим следующее:

CalledProcessError: Command '['D:\\***\\python.exe', '-c', "raise ValueError('It seems there is a mistake!')"]' returned non-zero exit status 1.

Мы получили ошибку. Для того, чтобы исключение возникало на этапе выполнения подпроцесса, необходимо указать параметр check = True.

В этом случае код не выполнится, и мы сразу будем знать, что в процессе возникла какая-то проблема.

Ограничение времени выполнения

Мы можем включить ограничение времени выполнения подпроцесса, чтобы программа, которая работает некорректно, не исполнялась бесконечно. Для этого используется параметр timeout:

run('ping yandex.ru', shell = True, timeout=5, capture_output = True, encoding='cp866')

В случае, если команда выполнилась, мы получим ее вывод:

Обмен пакетами с yandex.ru [77.88.55.50] с 32 байтами данных:
Ответ от 77.88.55.50: число байт=32 время=17мс TTL=56
Ответ от 77.88.55.50: число байт=32 время=17мс TTL=56
Ответ от 77.88.55.50: число байт=32 время=17мс TTL=56
Ответ от 77.88.55.50: число байт=32 время=17мс TTL=56

Если же наша команда не успела закончить выполнение за отведенное время, мы получаем исключение:

TimeoutExpired: Command 'ping yandex.ru' timed out after 1 seconds

С помощью подпроцессов мы также можем запускать установленные программы. Например:

run("notepad.exe")

откроет блокнот.

Также мы можем передавать какой-либо ввод используя stdin и параметр input. Выполним код:

run([executable, "-c", "from sys import stdin; print(stdin.read())"], input="Hello subprocess!",capture_output=True, encoding='cp866')

В результате мы получим:

Hello subprocess!

Через Input можно передавать не только определенный текст, но и вывод программы.

Функция subprocess.run

Функция run модуля Subprocess является высокоуровневой. Если для нашей задачи требуется бо́льшая гибкость, то можно использовать напрямую класс Popen. Он имеет схожий синтаксис, однако у него есть несколько дополнительных параметров.

Создадим 2 подпроцесса. В первом мы получим содержимое папки, а с помощью второго выполним сортировку. Чтобы использовать вывод результата первого подпроцесса, мы указываем для него stdout=PIPE (это значение, которое можно использовать в качестве аргумента для stdin, stdout или stderr).

Чтобы создать связь между двумя процессами, используется метод communicate().

p1 = Popen('dir', shell=True, stdin=None, stdout=PIPE, stderr=PIPE)
p2 = Popen('sort /R', shell=True, stdin=p1.stdout)
p1.stdout.close()
out, err = p2.communicate()

Результатом работы этого кода будет вывод отсортированных файлов в папке:

21.03.2022  12:35    <DIR>       ..
21.03.2022  12:35    <DIR>      .
21.03.2022  12:35           256 test1.py
21.03.2022  12:34           255 test3.py
21.03.2022  12:21           247 test5.py
21.03.2022  12:21           247 test4.py
21.03.2022  12:21           247 test2.py
21.03.2022  12:21           247 test.py

Класс Popen имеет также несколько других полезных методов:

  • poll() — проверяет, завершён ли дочерний процесс. Возвращает либо код выполнения, либо None, если процесс еще выполняется.
  • wait(timeout=None) — ждет завершения дочернего процесса, если указан timeout, то завершается по истечению указанного времени и вызывает исключение TimeoutExpired.
  • terminate() — останавливает выполнение процесса.

Заключение

В сегодняшней статье мы рассмотрели, как, используя Python, запустить внешние процессы. Это стандартная возможность библиотеки Python, позволяющая запускать внешние программы и осуществлять вывод.

Зарегистрируйтесь и начните пользоваться
сервисами Timeweb Cloud прямо сейчас

15 лет опыта
Сосредоточьтесь на своей работе: об остальном позаботимся мы
165 000 клиентов
Нам доверяют частные лица и компании, от небольших фирм до корпораций
Поддержка 24/7
100+ специалистов поддержки, готовых помочь в чате, тикете и по телефону