Subprocess.run: примеры (PYTHON)
subprocess.run(args, capture_output, shell, timeout, check, ...): subprocess.CompletedProcessФункция subprocess.run в Python
Функция subprocess.run представляет собой основной интерфейс модуля subprocess для выполнения внешних команд. Она применяется в ситуациях, когда требуется запустить отдельный процесс, дождаться его завершения и получить результат выполнения. Этот подход заменяет ряд устаревших функций, таких как os.system и os.spawn*.
Аргументы функции
- args: обязательный аргумент, принимающий строку или последовательность строк (список, кортеж). Если передается строка, интерпретация зависит от shell. При передаче списка первый элемент определяет команду, последующие - её аргументы.
- capture_output: при значении True происходит перехват stdout и stderr. Альтернатива ручному указанию subprocess.PIPE для stdout и stderr. Появился в Python 3.7.
- cwd: строка, указывающая рабочую директорию для выполнения команды.
- env: словарь с переменными окружения. Если None, используется окружение текущего процесса.
- check: если установлено True, при ненулевом коде возврата вызывается исключение CalledProcessError.
- shell: при True команда выполняется через системный shell (например, /bin/sh). Позволяет использовать shell-специфичные конструкции, но требует осторожности из-за рисков безопасности.
- text (ранее universal_newlines): при True потоки ввода/вывода открываются в текстовом режиме с кодировкой по умолчанию.
- encoding: кодировка для текстовых потоков.
- errors: обработка ошибок кодировки/декодировки.
- timeout: время в секундах, по истечении которого процесс будет прерван с генерацией TimeoutExpired.
- stdin, stdout, stderr: определяют стандартные потоки процесса. Возможные значения: subprocess.PIPE, subprocess.DEVNULL, существующий файловый дескриптор или открытый файловый объект.
Возвращаемое значение
Функция возвращает объект CompletedProcess, содержащий следующие атрибуты:
- args: аргументы, переданные для выполнения.
- returncode: код возврата процесса. Нулевое значение обычно означает успешное выполнение.
- stdout: перехваченный стандартный вывод (байты или строка в зависимости от text).
- stderr: перехваченный стандартный вывод ошибок.
Примеры использования subprocess.run
Простой вызов команды
import subprocess
result = subprocess.run(["echo", "Hello, World!"])
print(f"Return code: {result.returncode}")Return code: 0
Захват вывода
import subprocess
result = subprocess.run(["ls", "-l"], capture_output=True, text=True)
print("Stdout:")
print(result.stdout)
print(f"Stderr: {result.stderr}")Stdout: total 0 -rw-r--r-- 1 user group 0 Jan 1 00:00 file.txt Stderr:
Проверка кода возврата с исключением
import subprocess
try:
result = subprocess.run(["false"], check=True)
except subprocess.CalledProcessError as e:
print(f"Command failed with code {e.returncode}")Command failed with code 1
Использование shell
import subprocess
result = subprocess.run("echo $HOME", shell=True, capture_output=True, text=True)
print(f"Home directory: {result.stdout.strip()}")Home directory: /home/user
Установка таймаута
import subprocess
try:
result = subprocess.run(["sleep", "5"], timeout=2)
except subprocess.TimeoutExpired:
print("Process timed out")Process timed out
Похожие функции в Python
В модуле subprocess существуют дополнительные функции для запуска процессов:
- subprocess.Popen: базовый класс для создания и управления процессами. Предоставляет большую гибкость, но требует ручного управления. Используется, когда необходим асинхронный запуск или взаимодействие с процессом во время его выполнения.
- subprocess.call и subprocess.check_call: устаревшие функции, возвращающие только код возврата. check_call генерирует исключение при ненулевом коде.
- subprocess.check_output: возвращает вывод команды, генерируя исключение при ошибке. Удобна для сценариев, где требуется только результат выполнения.
- subprocess.getstatusoutput: возвращает кортеж (код возврата, вывод). Выполняется через shell.
subprocess.run рекомендуется как универсальная замена для большинства сценариев, объединяющая возможности предыдущих функций.
Аналоги функции в других языках
PHP
// exec - возвращает последнюю строку вывода
$output = exec('ls -l', $fullOutput, $returnCode);
echo "Output: $output\n";
print_r($fullOutput);Output: total 0
Array
(
[0] => total 0
[1] => -rw-r--r-- 1 user group 0 Jan 1 00:00 file.txt
)JavaScript (Node.js)
const { execSync } = require('child_process');
const output = execSync('echo Hello', { encoding: 'utf8' });
console.log(output);Hello
Java
import java.io.IOException;
Process process = Runtime.getRuntime().exec("echo Hello");
process.waitFor();
int exitCode = process.exitValue();
System.out.println("Exit code: " + exitCode);Exit code: 0
C#
using System.Diagnostics;
ProcessStartInfo startInfo = new ProcessStartInfo("echo", "Hello");
startInfo.RedirectStandardOutput = true;
Process process = Process.Start(startInfo);
string output = process.StandardOutput.ReadToEnd();
process.WaitForExit();
Console.WriteLine($"Output: {output}");Output: Hello
Golang
package main
import (
"fmt"
"os/exec"
)
func main() {
out, err := exec.Command("echo", "Hello").Output()
if err != nil {
fmt.Println(err)
}
fmt.Println(string(out))
}Hello
Kotlin
import java.lang.ProcessBuilder
val process = ProcessBuilder("echo", "Hello").start()
val output = process.inputStream.bufferedReader().readText()
process.waitFor()
println("Output: $output")Output: Hello
Основные отличия от Python реализации заключаются в способе передачи аргументов, обработки потоков ввода-вывода и исключений.
Типичные ошибки при использовании
Использование строки с аргументами без shell=True
import subprocess
# Ошибка: команда с аргументами как одна строка
result = subprocess.run("ls -l")FileNotFoundError: [Errno 2] No such file or directory: 'ls -l'
Неверная обработка вывода
import subprocess
result = subprocess.run(["echo", "test"], capture_output=True)
print(result.stdout) # вывод в байтах без декодированияb'test\n'
Бесконечное ожидание при чтении из pipe
import subprocess
# Дочерний процесс ждет ввода, а родительский - вывода
result = subprocess.run(["cat"], input="", capture_output=True, text=True)# Процесс зависает, ожидая ввода
Использование shell=True с ненадежными данными
import subprocess
user_input = "; rm -rf /" # опасная команда
subprocess.run(f"echo {user_input}", shell=True)Это может привести к выполнению произвольных команд. Рекомендуется использовать список аргументов или экранирование.
Изменения в последних версиях Python
- Python 3.5: появилась функция subprocess.run, заменившая несколько старых функций.
- Python 3.6: добавлен параметр encoding и errors.
- Python 3.7: введен параметр capture_output как упрощение для capture stdout и stderr. Добавлен текст в исключение TimeoutExpired.
- Python 3.8: в Windows улучшена обработка Ctrl+C.
- Python 3.9: параметр text стал предпочтительным синонимом для universal_newlines.
- Python 3.10: добавлена возможность передачи os.PathLike объектов в cwd.
- Python 3.11: улучшена производительность на Windows.
Расширенные примеры использования
Передача данных в стандартный ввод
import subprocess
# Передача строки в stdin процесса
result = subprocess.run(
["grep", "python"],
input="hello\npython world\ngoodbye\n",
capture_output=True,
text=True
)
print(f"Found: {result.stdout}")Found: python world
Использование переменных окружения
import subprocess
import os
custom_env = os.environ.copy()
custom_env["MY_VAR"] = "custom_value"
result = subprocess.run(
["printenv", "MY_VAR"],
env=custom_env,
capture_output=True,
text=True
)
print(f"Variable value: {result.stdout.strip()}")Variable value: custom_value
Параллельный запуск процессов
import subprocess
from concurrent.futures import ThreadPoolExecutor
def run_command(cmd):
return subprocess.run(cmd, capture_output=True, text=True)
commands = [
["sleep", "1"],
["echo", "hello"],
["ls", "-la"]
]
with ThreadPoolExecutor() as executor:
results = list(executor.map(run_command, commands))
for res in results:
print(f"Command completed with code {res.returncode}")Command completed with code 0 Command completed with code 0 Command completed with code 0
Обработка stderr отдельно от stdout
import subprocess
import sys
result = subprocess.run(
["ls", "nonexistent_file", "-la"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
if result.returncode != 0:
print(f"Error occurred: {result.stderr}", file=sys.stderr)
else:
print(result.stdout)Error occurred: ls: cannot access 'nonexistent_file': No such file or directory
Использование cwd для смены рабочей директории
import subprocess
import tempfile
import os
with tempfile.TemporaryDirectory() as tmpdir:
# Создаем файл во временной директории
test_file = os.path.join(tmpdir, "test.txt")
with open(test_file, "w") as f:
f.write("content")
# Запускаем ls во временной директории
result = subprocess.run(
["ls", "-l"],
cwd=tmpdir,
capture_output=True,
text=True
)
print(f"Files in temp directory:\n{result.stdout}")Files in temp directory: total 4 -rw-r--r-- 1 user group 7 Jan 1 00:00 test.txt
Комбинирование stderr с stdout
import subprocess
# Перенаправляем stderr в stdout
result = subprocess.run(
["ls", "existing_file", "nonexistent_file"],
stdout=subprocess.PIPE,
stderr=subprocess.STDOUT, # особое значение
text=True
)
print(f"Combined output:\n{result.stdout}")Combined output: existing_file ls: cannot access 'nonexistent_file': No such file or directory