Subprocess.call: примеры (PYTHON)
subprocess.call(args, stdin, stdout, stderr, shell, timeout): intОсновы функции subprocess.call
Функция subprocess.call() в модуле subprocess предназначена для запуска внешних команд и программ из Python-скрипта. Эта функция часто используется, когда требуется выполнить системную команду, другой исполняемый файл или скрипт, и дождаться завершения его работы. Основное применение связано с автоматизацией системных задач, интеграцией со сторонним ПО или выполнением команд оболочки.
Аргументы функции:
- args: обязательный аргумент. Может быть строкой или последовательностью (список, кортеж). Для строки интерпретация зависит от аргумента shell. Для последовательности первый элемент - это исполняемая команда, остальные - её аргументы.
- stdin: стандартный ввод для дочернего процесса. По умолчанию None, что означает перенаправление из файла /dev/null. Может быть файловым объектом, файловым дескриптором или subprocess.PIPE.
- stdout: стандартный вывод. Аналогично stdin, по умолчанию None (вывод направляется в консоль).
- stderr: стандартный вывод ошибок. По умолчанию None (ошибки направляются в консоль).
- shell: логическое значение. Если True, команда выполняется через оболочку системы (обычно /bin/sh в Unix). Это позволяет использовать возможности оболочки, такие как подстановка файлов или переменные среды, но может быть источником уязвимостей при использовании пользовательского ввода.
- cwd: строка, указывающая текущий рабочий каталог для выполнения команды.
- timeout: время в секундах, по истечении которого функция завершится с исключением TimeoutExpired. Доступно в Python 3.3+.
- env: словарь с переменными среды для дочернего процесса. Если None, используется окружение текущего процесса.
Возвращаемое значение: целое число - код завершения дочернего процесса. Обычно 0 означает успешное выполнение, другие значения указывают на ошибку (код зависит от конкретной команды). Если процесс завершился по сигналу, возвращается отрицательный номер сигнала.
Примеры использования subprocess.call
Пример 1: Простой вызов команды ls (Unix/Linux) или dir (Windows).
import subprocess # Для Unix/Linux return_code = subprocess.call([\"ls\", \"-l\"]) print(\"Код возврата:\", return_code)
Код возврата: 0
Пример 2: Использование оболочки с аргументом shell=True.
import subprocess # Через оболочку return_code = subprocess.call(\"echo Hello, World!\", shell=True) print(\"Код возврата:\", return_code)
Hello, World! Код возврата: 0
Пример 3: Задание рабочего каталога и обработка таймаута.
import subprocess
import time
try:
# Команда sleep на 10 секунд, но таймаут 2 секунды
return_code = subprocess.call([\"sleep\", \"10\"], timeout=2)
except subprocess.TimeoutExpired:
print(\"Процесс не завершился за отведенное время\")Процесс не завершился за отведенное время
Похожие функции в Python
Модуль subprocess предлагает несколько функций для выполнения внешних команд, каждая со своими особенностями.
- subprocess.run(): рекомендованная функция в Python 3.5+. Возвращает объект CompletedProcess, содержащий код возврата, stdout и stderr. Более гибкая и функциональная, чем call.
- subprocess.check_call(): аналогична call, но генерирует исключение CalledProcessError, если код возврата не нулевой.
- subprocess.check_output(): возвращает вывод команды (stdout) в виде байтовой строки. Также генерирует исключение при ненулевом коде возврата.
- subprocess.Popen(): низкоуровневый интерфейс для создания процессов. Предоставляет максимальный контроль: неблокирующее выполнение, передача данных через каналы, ожидание завершения отдельным вызовом. Используется, когда требуется сложное взаимодействие с процессом.
subprocess.call() предпочтительнее для простых задач, где нужен только код возврата, и не требуется захват вывода. Для большинства новых проектов рекомендуется использовать subprocess.run() из-за её больших возможностей и понятного API.
Аналоги в других языках программирования
Разные языки предоставляют свои механизмы для запуска внешних процессов.
PHP: функция exec() или shell_exec().
<?php $output = exec(\"ls -l\", $output_array, $return_code); echo \"Код возврата: \" . $return_code . \"\\n\"; ?>
Код возврата: 0
JavaScript (Node.js): модуль child_process, функция exec() или spawn().
const { exec } = require(\"child_process\");
exec(\"ls -l\", (error, stdout, stderr) => {
console.log(`Код возврата: ${error ? error.code : 0}`);
});Код возврата: 0
Java: класс ProcessBuilder или Runtime.exec().
import java.io.IOException;
public class Main {
public static void main(String[] args) throws IOException, InterruptedException {
Process process = new ProcessBuilder(\"ls\", \"-l\").start();
int exitCode = process.waitFor();
System.out.println(\"Код возврата: \" + exitCode);
}
}Код возврата: 0
Go: пакет os/exec, метод Run().
package main
import (
\"fmt\"
\"os/exec\"
)
func main() {
cmd := exec.Command(\"ls\", \"-l\")
err := cmd.Run()
if err != nil {
fmt.Println(\"Код возврата (ошибка):\", err)
} else {
fmt.Println(\"Код возврата: 0\")
}
}Код возврата: 0
Основное отличие Python в простоте использования и наличии нескольких функций для разных сценариев. В Python часто код получается более кратким и читаемым для типичных задач.
Типичные ошибки при использовании
Ошибка 1: Неправильный путь к исполняемому файлу или команда не найдена.
import subprocess
try:
subprocess.call([\"non_existent_command\"])
except FileNotFoundError as e:
print(\"Ошибка:\", e)Ошибка: [Errno 2] No such file or directory: 'non_existent_command'
Ошибка 2: Использование строки с аргументами без shell=True, когда команда содержит пробелы или специальные символы.
import subprocess # Неправильно: строка без shell=True разбивается неправильно subprocess.call(\"ls -l\") # Ищет команду с именем 'ls -l' (с пробелом)
FileNotFoundError: [Errno 2] No such file or directory: 'ls -l'
Правильный подход: либо использовать список, либо установить shell=True.
Ошибка 3: Проблемы с безопасностью при использовании shell=True с пользовательским вводом.
import subprocess
user_input = \"; rm -rf /\" # Опасная команда
# Никогда так не делать!
# subprocess.call(f\"echo {user_input}\", shell=True)Во избежание инъекций команд рекомендуется использовать списки аргументов и избегать shell=True, когда возможен пользовательский ввод.
Изменения в последних версиях Python
В Python 3.5 была введена функция subprocess.run(), которая стала рекомендуемой заменой для call, check_call и check_output. Однако subprocess.call() остаётся доступной для обратной совместимости.
В Python 3.3 был добавлен параметр timeout для call, check_call и check_output. При превышении таймаута генерируется исключение TimeoutExpired.
Начиная с Python 3.8, в subprocess.run() (и другие функции) добавлен параметр capture_output для удобства захвата stdout и stderr. Однако subprocess.call() не получила этого параметра, так как не предназначена для захвата вывода.
В Python 3.12 были оптимизированы некоторые внутренние аспекты работы модуля subprocess, но публичный API call не претерпел значительных изменений.
Расширенные примеры использования
Пример 1: Запуск команды с перенаправлением стандартного вывода в файл.
import subprocess
with open(\"output.txt\", \"w\") as f:
return_code = subprocess.call([\"ls\", \"-l\"], stdout=f)
print(\"Код возврата:\", return_code)
# Содержимое файла output.txt будет содержать вывод ls -lКод возврата: 0
Пример 2: Использование переменных среды для дочернего процесса.
import subprocess import os custom_env = os.environ.copy() custom_env[\"MY_VAR\"] = \"Hello\" # Передаем собственное окружение return_code = subprocess.call([\"printenv\", \"MY_VAR\"], env=custom_env) print(\"Код возврата:\", return_code)
Hello Код возврата: 0
Пример 3: Выполнение команды с разными кодами возврата и их интерпретация.
import subprocess # Команда test возвращает 0, если условие истинно, иначе 1 return_code = subprocess.call([\"test\", \"1\", \"-eq\", \"1\"]) print(\"Код возврата при истинном условии:\", return_code) return_code = subprocess.call([\"test\", \"1\", \"-eq\", \"2\"]) print(\"Код возврата при ложном условии:\", return_code)
Код возврата при истинном условии: 0 Код возврата при ложном условии: 1
Пример 4: Комбинирование stderr и stdout с использованием subprocess.STDOUT.
import subprocess
# stderr перенаправляется в stdout
return_code = subprocess.call(
[\"ls\", \"-l\", \"non_existent_file\"],
stderr=subprocess.STDOUT
)
print(\"Код возврата:\", return_code)ls: cannot access 'non_existent_file': No such file or directory Код возврата: 2
Пример 5: Выполнение команды в оболочке с передачей сложной строки.
import subprocess # Использование возможностей оболочки: подстановка команд и перенаправление cmd = \"echo Current user: $(whoami) > user_info.txt\" return_code = subprocess.call(cmd, shell=True) print(\"Код возврата:\", return_code) # В файле user_info.txt будет строка \"Current user: username\"
Код возврата: 0