Python 3 subprocess

05 Мар 2021 , 659

Иногда возникает необходимость запустить определенную программу на вашем компьютере или выполнить команды в операционной системе 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:

  1. Гибкость управления процессом: 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. Затем мы взаимодействуем с ним, отправляя данные в его стандартный ввод, читая вывод в режиме реального времени и прерывая выполнение при необходимости. После прерывания, мы читаем оставшийся вывод процесса и получаем его код завершения.

  2. Потоки ввода и вывода: Вы можете легко работать с потоками ввода и вывода, когда используете 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, что может быть полезным для создания интерактивных приложений или обработки длительных задач с пошаговым выполнением.

  3. Поддержка больших данных: Если вам нужно обрабатывать большие объемы данных, 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 предоставляет большую гибкость для более сложных задач.

comments powered by Disqus

Подписка

Подпишитесь на наш список рассылки, чтобы получать обновления из блога

Рубрики

Теги