Python 3 subprocess
Иногда возникает необходимость запустить определенную программу на вашем компьютере или выполнить команды в операционной системе Linux из Python кода
Модуль subprocess был введен в Python с целью предоставить более мощный и гибкий способ выполнения внешних команд и программ из Python кода. Это произошло в Python 2.4. Модуль subprocess предоставил более современный и надежный способ выполнения внешних команд по сравнению с устаревшими модулями os.system и os.spawn.
В Python 2.6 была добавлена поддержка дополнительных параметров и функций для управления потоками ввода и вывода, что сделало модуль subprocess еще более мощным. С появлением Python 3.0 и последующими версиями, модуль subprocess стал стандартным и заменил устаревший модуль commands
С версии python 3.5 появилась функция run, которая является предпочитаемым способом использования для всех возможных случаев.
Как сказано в официальной документации , модуль subprocess позволяет создавать новые процессы , подключаться к их каналам ввода-вывода и получать их коды возрата.
import subprocess
# Запуск команды "ls -l" в командной оболочке и получение ее вывода
result = subprocess.run(["ls", "-l"], stdout=subprocess.PIPE, text=True)
print(result.stdout)
В этом примере мы запускаем команду ls -l, которая выводит список файлов и папок в текущем каталоге. Мы используем аргумент stdout=subprocess.PIPE, чтобы перенаправить вывод команды в переменную result.stdout. Параметр text=True используется для того, чтобы получить текстовый вывод.
Модуль subprocess также предоставляет более гибкий способ управления процессами с использованием subprocess.Popen. Этот метод может быть полезен, если вам нужно более тонко настраивать процесс или работать с его потоками ввода и вывода.
subprocess.Popen и subprocess.run предоставляют разные уровни контроля и гибкости при выполнении внешних команд из Python. Вот некоторые преимущества subprocess.Popen перед subprocess.run:
-
Гибкость управления процессом: subprocess.Popen предоставляет более гибкий контроль над процессом. Вы можете управлять вводом и выводом процесса, отправлять сигналы процессу и манипулировать им в более сложных сценариях.
Покажем это на примере:
import subprocess import time # Создание объекта Popen для команды "cat" process = subprocess.Popen(["cat"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) try: # Отправляем данные в стандартный ввод процесса process.stdin.write("Hello, subprocess!\n") process.stdin.flush() # Читаем вывод процесса output = process.stdout.readline().strip() print(f"Процесс выдал: {output}") # Даем немного времени на обработку time.sleep(2) # Прерываем выполнение процесса process.terminate() # Читаем оставшийся вывод процесса после прерывания remaining_output = process.stdout.read() print(f"Оставшийся вывод: {remaining_output}") except KeyboardInterrupt: # Обработка прерывания пользователем print("Процесс был прерван пользователем.") finally: # Завершаем процесс process.wait() # Выводим код завершения print(f"Код завершения: {process.returncode}")
В данном коде мы инициируем процесс выполнения команды cat. Затем мы взаимодействуем с ним, отправляя данные в его стандартный ввод, читая вывод в режиме реального времени и прерывая выполнение при необходимости. После прерывания, мы читаем оставшийся вывод процесса и получаем его код завершения.
Потоки ввода и вывода: Вы можете легко работать с потоками ввода и вывода, когда используете subprocess.Popen. Например, вы можете отправлять данные в стандартный ввод процесса или читать вывод по кускам, что полезно для интерактивных приложений или длительных задач
В этом примере мы будем запускать процесс Python, который будет читать данные из своего стандартного ввода и выводить их в стандартный вывод. Мы будем отправлять данные в стандартный ввод процесса по кускам и читать его вывод по мере поступления.
import subprocess # Создание объекта Popen для запуска streaming_example.py process = subprocess.Popen( ["python", "streaming_example.py"], stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) try: # Отправка данных в стандартный ввод процесса по кускам for i in range(5): data = f"Сообщение {i}\n" process.stdin.write(data) process.stdin.flush() # Чтение вывода процесса по мере поступления while True: line = process.stdout.readline() if not line: break print(line.strip()) except KeyboardInterrupt: # Обработка прерывания пользователем print("Процесс был прерван пользователем.") finally: # Завершение процесса process.terminate() process.wait() # Вывод кода завершения print(f"Код завершения: {process.returncode}")
Мы отправляем данные в стандартный ввод процесса по частям в цикле. Читаем вывод процесса по мере его поступления, находясь в бесконечном цикле, пока процесс активен. При необходимости мы прерываем выполнение процесса. Завершаем работу процесса и выводим код его завершения. Этот код иллюстрирует, как эффективно взаимодействовать с потоками ввода и вывода при выполнении процессов в Python, что может быть полезным для создания интерактивных приложений или обработки длительных задач с пошаговым выполнением.
Поддержка больших данных: Если вам нужно обрабатывать большие объемы данных, subprocess.Popen позволяет работать с потоками вывода и избегать хранения всего вывода в памяти.
Вот пример кода, который демонстрирует, как это можно сделать:
import subprocess # Команда для выполнения (например, вывод файла с большим объемом данных) command = ["cat", "large_file.txt"] # Создание объекта Popen process = subprocess.Popen(command, stdout=subprocess.PIPE, text=True) # Чтение вывода по порциям и обработка данных chunk_size = 1024 # Размер порции данных для чтения while True: chunk = process.stdout.read(chunk_size) if not chunk: break # Обработка данных (например, запись в файл) # Здесь можно добавить вашу логику обработки данных with open("output_file.txt", "a") as output_file: output_file.write(chunk) # Ожидание завершения выполнения команды и получение кода завершения return_code = process.wait() # Вывод кода завершения print(f"Код завершения: {return_code}")
В этом примере мы используем subprocess.Popen для выполнения команды cat large_file.txt, которая выводит содержимое большого файла large_file.txt. Мы читаем вывод по кускам (chunk) и обрабатываем каждый кусок данных, например, записывая его в другой файл. Это позволяет избежать загрузки всего вывода в память и обрабатывать большие объемы данных по мере их поступления.
Заключение
Модуль subprocess в Python представляет собой мощный инструмент для выполнения внешних команд и программ из Python кода. Он обеспечивает гибкое управление процессами, взаимодействие с их потоками ввода и вывода, а также обработку кодов завершения. Два основных способа работы с subprocess - это методы run и Popen.
Метод subprocess.run предоставляет простой и удобный интерфейс для выполнения команд и получения результатов их выполнения. Он позволяет контролировать ввод, вывод, код завершения и многое другое, делая выполнение команд более прозрачным и удобным.
Метод subprocess.Popen с другой стороны, предоставляет более гибкий контроль над процессами. Он позволяет манипулировать вводом и выводом процесса, отправлять сигналы, работать с потоками и обрабатывать более сложные сценарии взаимодействия.
Выбор между subprocess.run и subprocess.Popen зависит от конкретных требований вашего проекта. subprocess.run подходит для простых сценариев выполнения команд, в то время как subprocess.Popen предоставляет большую гибкость для более сложных задач.