Запуск инструкций командной строки из Python
Мостиком для взаимодействия Python и командной строки служит модуль subprocess. С его помощью можно выполнить команду и получить результат ее работы прямо из кода. Предпочтительным способом запуска является функция run.
command
По умолчанию первым аргументом run передается список из команды и ее параметров. Этого достаточно для запуска:
import subprocess subprocess.run(['ls', '-la'])
shell
Также можно задать первый аргумент как строку, но тогда нужно указать флаг shell=True:
subprocess.run('ls -la') subprocess.run('ls -la', shell=True)
capture_output
Опционально можно перехватить потоки вывода и ошибок путем установки флага capture_output=True:
res = subprocess.run('ls -la', shell=True, capture_output=True) print(res.stdout.decode('utf8')) print(res.returncode)
res = subprocess.run('ls w', shell=True, capture_output=True) print(res.returncode) print(res.stderr.decode('utf8'))
text
В stdout и stderr по умолчанию возвращается байтовые строки, которые надо декодировать. Иначе можно установить флаг text:
res = subprocess.run('ls -la', shell=True, capture_output=True) print(res.stdout)
res = subprocess.run('ls -la', shell=True, text=True, capture_output=True) print(res.stdout)
encoding
По умолчанию декодирование происходит с кодировкой, которую можно получить так:
import locale locale.getpreferredencoding(False)
Иначе можно задать свою кодировку в параметре encoding.
timeout
Аргумент timeout задает максимальное время (в секундах) ожидания выполнения команды, после выбрасывается исключение TimeoutExpired:
subprocess.run('ls -l', shell=True, capture_output=True, timeout=0.1) subprocess.run('ls -l', shell=True, capture_output=True, timeout=0.001)
check
Если установить флаг check, то при ненулевом коде возврата будет генерироваться исключение CalledProcessError:
subprocess.run('ls -l', shell=True, check=True) subprocess.run('ls w', shell=True, check=True)
input
В параметре input можно задать значение, которое будет передано в stdin:
import sys result = subprocess.run( [sys.executable, "-c", "import sys; print(sys.stdin.read())"], capture_output=True, text=True, input="hello" ) result.stdout
Popen
Внутри run обращается к объекту класса Popen, который обладает более гибкими, но и сложными настройками:
res = subprocess.Popen('ls -la', shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, text=True).communicate() # stdout print(res[0])
res = subprocess.Popen('ls w', shell=True, stderr=subprocess.PIPE, stdout=subprocess.PIPE, text=True).communicate() # stderr print(res[1])
Интерфейс вызова через класс Popen немного отличается. Главное, что посредством вызова метода communicate запускается дочерней процесс, которому в stdin отправляются данные и считывается результат из stdout и stderr. Для взаимодействия с потоками ввода/вывода указывайте в соответствующих параметрах значение PIPE (метод run так и поступает при capture_output=True).