Какие способы запуска команд есть в Python

Раздел: Разработка на Python -> Запуск Python кода

Базовый способ выполнения команды в Python

Модуль subprocess входит в стандартную библиотеку и является основным для запуска внешних процессов. Функция subprocess.run принимает список слов команды, запускает процесс, ожидает его завершения и возвращает объект CompletedProcess. Такой подход подходит для выполнения команды в Python, когда нужно дождаться результата, получить код возврата, stdout или stderr.


import subprocess

result = subprocess.run(['echo', 'hello'], capture_output=True, text=True)
print(result.stdout)
print(result.returncode)

Python выполнить команду (выполнение команды в python)

hello
0

Параметр capture_output=True собирает стандартный вывод и ошибки. text=True преобразует байты в строку. Если команда не найдена, поднимается FileNotFoundError, а если задан check=True и код возврата не равен нулю, поднимается CalledProcessError.


import subprocess

try:
    subprocess.run(['false'], check=True)
except subprocess.CalledProcessError as err:
    print('Код возврата:', err.returncode)
Код возврата: 1

Для команд с аргументами удобнее передавать список, а не строку. Это избавляет от необходимости экранировать пробелы и специальные символы. Если команда записана строкой, её разбирает shlex.split, но можно также указать shell=True.

Как выполнить команду в Python без получения её вывода?

Функция os.system из модуля os передаёт строку командному интерпретатору и возвращает код завершения. Она удобна для простых действий, результат которых не нужен в скрипте.


import os

code = os.system('ls -la')
print('Код:', code)
(вывод команды ls)
Код: 0

Вывод уходит в стандартный поток процесса Python, поэтому поймать его переменной нельзя. Строка передаётся оболочке, и при подстановке пользовательских данных возможна инъекция. Для безопасной передачи аргументов используют shlex.quote и список из subprocess.run.

Как получить вывод команды быстро?

Функция os.popen открывает однонаправленный канал от процесса. Метод read() возвращает весь вывод. Этот вариант встречается в старом коде и подходит для коротких команд.


import os

output = os.popen('date').read()
print('Сегодня:', output.strip())
Сегодня: Wed Jan 25 12:34:56 MSK 2025

os.popen не позволяет разделить stdout и stderr. Код возврата доступен только после закрытия канала. Для новых проектов лучше использовать subprocess, так как он предоставляет больше контроля над процессом.

Как выполнить команду в Python и сразу получить stdout?

subprocess.check_output принимает список аргументов, выполняет команду и возвращает stdout в виде байтовой строки. При ненулевом коде завершения возникает CalledProcessError, внутри которого есть атрибуты output, returncode, stderr.


import subprocess

try:
    out = subprocess.check_output(['printf', 'abc'])
except subprocess.CalledProcessError as err:
    print('Ошибка:', err.returncode)
else:
    print(repr(out))
b'abc'

Для работы с текстом удобно передать encoding='utf-8', тогда функция вернёт строку.


out = subprocess.check_output(['echo', 'hello'], encoding='utf-8')
print(out.strip())
hello

Как выполнить команду в Python с чтением вывода по мере поступления?

subprocess.Popen запускает процесс в фоне и даёт управление немедленно. С помощью communicate() можно дождаться завершения и собрать stdout и stderr. Для построчного чтения используют цикл по stdout процесса.


import subprocess

proc = subprocess.Popen(['ping', '-c', '3', '127.0.0.1'], stdout=subprocess.PIPE, text=True)
for line in proc.stdout:
    print('line:', line.strip())
proc.wait()
print('returncode:', proc.returncode)
line: PING 127.0.0.1 (127.0.0.1) 56(84) bytes of data.
line: 64 bytes from 127.0.0.1: icmp_seq=1 ttl=64 time=0.042 ms
line: 64 bytes from 127.0.0.1: icmp_seq=2 ttl=64 time=0.035 ms
line: 64 bytes from 127.0.0.1: icmp_seq=3 ttl=64 time=0.039 ms
returncode: 0

Если не читать stdout в цикле, канал может переполниться и процесс заблокируется. При использовании communicate() этого можно избежать, но весь вывод собирается в памяти.

Как выполнить строку команды с операторами оболочки?

Иногда команда содержит пайпы, перенаправление или переменные окружения. В таких случаях применяют subprocess.run со shell=True и передают полную строку. Чтобы безопасно подставить переменную, используют shlex.quote.


import subprocess
import shlex

filename = 'my file.txt'
cmd = 'cat ' + shlex.quote(filename) + ' | wc -l'
res = subprocess.run(cmd, shell=True, capture_output=True, text=True)
print(res.stdout)
42

shell=True запускает команду через /bin/sh. Если в строку попадают непроверенные данные, есть риск выполнения произвольных команд. Лучше передавать список аргументов и организовывать конвейер на стороне Python с помощью Popen.

Как передать данные в команду и ограничить время её работы?

Функция subprocess.run принимает параметр input для передачи строки или байтов в стандартный ввод дочернего процесса. Параметр timeout ограничивает время ожидания. Если процесс не завершится за указанное время, возникнет TimeoutExpired.


import subprocess

try:
    subprocess.run(['cat'], input='строка\n', text=True, timeout=5)
except subprocess.TimeoutExpired:
    print('Превышено время ожидания')
строка

Параметры cwd и env задают рабочую директорию и окружение процесса.


import subprocess
import os

env = os.environ.copy()
env['MY_VAR'] = 'value'
proc = subprocess.run(['pwd'], cwd='/tmp', env=env, capture_output=True, text=True)
print(proc.stdout)
/tmp

Как получить вывод команды без лишних объектов?

В subprocess есть функции getoutput и getstatusoutput. Они удобны для быстрых сценариев, но не дают детального контроля.


import subprocess

output = subprocess.getoutput('uname -m')
print('Архитектура:', output)

status, output = subprocess.getstatusoutput('ls /no/such/path')
print('Код:', status)
print('Вывод:', output)
Архитектура: x86_64
Код: 2
Вывод: ls: cannot access '/no/such/path': No such file or directory

getoutput выполняет команду через shell, поэтому с ней нужно обращаться аккуратно. getstatusoutput возвращает код и объединённый вывод, без разделения stdout и stderr.

Пример 1. Получение stdout и stderr по отдельности

Параметр capture_output=True сохраняет оба потока в объекте результата.

Пример

import subprocess

result = subprocess.run(['sh', '-c', 'echo out; echo err >&2'], capture_output=True, text=True)
print('stdout:', result.stdout.strip())
print('stderr:', result.stderr.strip())
print('code:', result.returncode)
stdout: out
stderr: err
code: 0

Пример 2. Проверка кода возврата с check_output

Функция возвращает байты, поэтому для текста её обычно вызывают с encoding или декодируют вручную.

Пример

import subprocess

out = subprocess.check_output(['printf', 'abc'])
print(out)
print(out.decode('utf-8'))
b'abc'
abc

Пример 3. Передача данных через stdin

Popen и communicate удобны для интерактивных программ, которым нужны данные на входе.

Пример

import subprocess

proc = subprocess.Popen(['sort'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
out, err = proc.communicate(input='banana\napple\ncherry\n')
print(out)
apple
banana
cherry

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

timeout останавливает ожидание и даёт процессу завершиться принудительно.

Пример

import subprocess

try:
    subprocess.run(['sleep', '10'], timeout=2)
except subprocess.TimeoutExpired:
    print('Процесс не завершился вовремя')
Процесс не завершился вовремя

Пример 5. Объединение stderr и stdout в один поток

Параметр stderr=subprocess.STDOUT направляет ошибки в стандартный вывод.

Пример

import subprocess

proc = subprocess.Popen(['sh', '-c', 'echo out; echo err >&2'], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True)
output = proc.communicate()[0]
print(output)
out
err

Пример 6. Запуск процесса в фоне с опросом состояния

Метод poll возвращает None, пока процесс работает, и код возврата после завершения.

Пример

import subprocess
import time

proc = subprocess.Popen(['sleep', '3'])
while proc.poll() is None:
    print('Работает...')
    time.sleep(1)
print('Завершён с кодом', proc.poll())
Работает...
Работает...
Завершён с кодом 0

Пример 7. Настройка переменных окружения

Для передачи в процесс копии текущего окружения используют os.environ.copy.

Пример

import subprocess
import os

env = os.environ.copy()
env['CUSTOM'] = 'hello'
res = subprocess.run(['sh', '-c', 'echo $CUSTOM'], env=env, capture_output=True, text=True)
print(res.stdout)
hello

Пример 8. Разбор командной строки с shlex.split

Когда команда приходит в виде строки, shlex.split превращает её в список аргументов без обращения к shell.

Пример

import subprocess
import shlex

cmd = 'echo hello world'
args = shlex.split(cmd)
print(args)
res = subprocess.run(args, capture_output=True, text=True)
print(res.stdout)
['echo', 'hello', 'world']
hello world

Пример 9. Запуск текущего интерпретатора Python

sys.executable указывает на исполняемый файл текущей версии Python. Это полезно для вложенных скриптов.

Пример

import subprocess
import sys

res = subprocess.run([sys.executable, '-c', 'print(2 ** 3)'], capture_output=True, text=True)
print(res.stdout)
8

Пример 10. Асинхронный запуск через asyncio

Модуль asyncio позволяет запускать внешние команды без блокировки основного потока.

Пример

import asyncio

async def run_command():
    proc = await asyncio.create_subprocess_exec(
        'echo', 'async',
        stdout=asyncio.subprocess.PIPE,
        stderr=asyncio.subprocess.PIPE,
    )
    stdout, stderr = await proc.communicate()
    print(stdout.decode().strip())

asyncio.run(run_command())
async

Пример 11. Подавление вывода команды

DEVNULL заменяет потоки пустыми файловыми дескрипторами, поэтому вывод не попадает никуда.

Пример

import subprocess

res = subprocess.run(['true'], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
print(res.returncode)
0

Пример 12. Конвейер между процессами без shell

Два вызова Popen соединяются через атрибут stdout первого процесса.

Пример

import subprocess

p1 = subprocess.Popen(['echo', 'hello'], stdout=subprocess.PIPE)
p2 = subprocess.Popen(['tr', 'a-z', 'A-Z'], stdin=p1.stdout, stdout=subprocess.PIPE, text=True)
p1.stdout.close()
out, _ = p2.communicate()
print(out)
HELLO

Выполнение команды в Python - comments

En
Python выполнить команду (python)