Какие способы запуска команд есть в 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