subprocess python
Introduction
В этой статье вы узнаете как выполнять команды
Linux
и
Windows
из кода на Python 3.
Создайте файл
subprocess_lesson.py
и копируйте туда код из примеров.
Запустить файл можно командой
python3 subprocess.py
Простой пример
Пример программы, которая выполняет Linux команду ls
import subprocess
subprocess.run('ls')
Простой пример Windows
Пример программы, которая выполняет в Windows команду dir
import subprocess
subprocess.run('dir', shell=True)
У меня пока что не работает
Bash команда с опциями
To выполнить Bash команду с опциями, например, ls - la нужно добавить shell=True
import subprocess
subprocess.run('ls -la', shell=True)
У использования shell=True есть одна важная особенность:
нужно особенно внимательно следить за безопастностью.
Рекомендуется использовать shell=True только если вы
передаёте параметры самостоятельно.
Избежать использования shell=True можно передав команду и параметры списком:
import subprocess
subprocess.run(['ls', '-la'])
Передать переменную в аргумент команды
По аналогии с предыдущим параграфом - в качестве аргумента можно использовать и переменную
import subprocess
text = "Visit TopBicycle.ru to support my website"
subprocess.run(["echo",text])
python3 subprocess_lesson.py
Visit TopBicycle.ru to support my website
args, returncode, stdout
Разберём subprocess более подробно
import subprocess
p1 = subprocess.run(['ls', '-la'])
print("p1")
print(p1)
print("p1.args")
print(p1.args)
print("p1.returncode")
print(p1.returncode)
print("p1.stdout")
print(p1.stdout)
python3 subprocess_lesson.py
total 12 drwxrwxr-x 2 andrei andrei 4096 Nov 30 17:57 . drwxrwxr-x 3 andrei andrei 4096 Nov 30 17:57 .. -rw-rw-r-- 1 andrei andrei 195 Nov 30 16:51 subprocess_lesson.py p1 CompletedProcess(args='ls -la', returncode=0) p1.args ls -la p1.returncode 0 p1.stdout None
To не выводить результат в терминал а сохранить в переменную, нужно воспользоваться опцией capture_output=True
import subprocess
p1 = subprocess.run(['ls', '-la'], capture_output=True)
print(p1.stdout)
python3 subprocess_lesson.py
b'total 12\ndrwxrwxr-x 2 andrei andrei 4096 Nov 30 18:41 .\ndrwxrwxr-x 3 andrei andrei 4096 Nov 30 18:40 ..\n-rw-rw-r-- 1 andrei andrei 92 Nov 30 18:41 subprocess_lesson.py\n'
Если byte вывод вам не нравится его можно декодировать
import subprocess
p1 = subprocess.run(['ls', '-la'], capture_output=True)
print(p1.stdout.decode())
python3 subprocess_lesson.py
total 12 drwxrwxr-x 2 andrei andrei 4096 Nov 30 18:41 . drwxrwxr-x 3 andrei andrei 4096 Nov 30 18:40 .. -rw-rw-r-- 1 andrei andrei 101 Nov 30 18:46 subprocess_lesson.py
Или можно использовать опцию text=True
import subprocess
p1 = subprocess.run(['ls', '-la'], capture_output=True, text=True)
print(p1.stdout)
total 12 drwxrwxr-x 2 andrei andrei 4096 Nov 30 18:41 . drwxrwxr-x 3 andrei andrei 4096 Nov 30 18:40 .. -rw-rw-r-- 1 andrei andrei 101 Nov 30 18:46 subprocess_lesson.py
Ещё один вариант перенаправления вывода stdout=subprocess.PIPE
import subprocess
p1 = subprocess.run(['ls', '-la'], stdout=subprocess.PIPE, text=True)
print(p1.stdout)
python3 subprocess_lesson.py
total 12 drwxrwxr-x 2 andrei andrei 4096 Nov 30 18:41 . drwxrwxr-x 3 andrei andrei 4096 Nov 30 18:40 .. -rw-rw-r-- 1 andrei andrei 101 Nov 30 18:46 subprocess_lesson.py
Вывод в файл
import subprocess
with open('output.txt', 'w') as f:
p1 = subprocess.run(['ls', '-la'], stdout=f, text=True)
Обработка ошибок
Добавим заведомо неверное условие в команду. Например, пусть листинг выполняется не для текущей директории а для несуществующей.
import subprocess
p1 = subprocess.run(['ls', '-la', 'not_exist'], capture_output=True, text=True)
print(p1.returncode)
print(p1.stderr)
2 ls: cannot access 'not_exist': No such file or directory
Обратите внимане, что Python в этом примере не выдаёт никаких ошибок
To Python информировал об ошибках во внешних командах используйте опцию check=True
import subprocess
p1 = subprocess.run(['ls', '-la', 'not_exist'], capture_output=True, text=True, check=True)
print(p1.returncode)
print(p1.stderr)
python3 subprocess_lesson.py
Traceback (most recent call last): File "subprocess_lesson.py", line 3, in <module> p1 = subprocess.run(['ls', '-la', 'not_exist'], capture_output=True, text=True, check=True) File "/usr/lib/python3.8/subprocess.py", line 512, in run raise CalledProcessError(retcode, process.args, subprocess.CalledProcessError: Command '['ls', '-la', 'not_exist']' returned non-zero exit status 2.
Обратите внимане, что теперь Python выдаёт ошибку, а до print(p1.returncode) и print(p1.stderr) дело уже не доходит
import subprocess
p1 = subprocess.run(['ls', '-la', 'not_exist'], stderr=subprocess.DEVNULL)
print(p1.stderr)
python3 subprocess_lesson.py
None
Передача аргументов в скрипт
Допустим, нужно вызвать скрипт с несколькими аргументами
import subprocess
subprocess.call(['./script.sh %s %s %s' %(ip, username, test_time)], shell=True)
Ещё пример: из python скрипта вызвать sed и обрезать число строк, которое сам скрипт получает как аргумент
import subprocess
LINES = int(sys.argv[1])
subprocess.call(['sed -i -e 1,%sd 2025-03-21-log.txt' %(LINES)], shell=True)
Эту задачу можно решить на чистом Python решение
with open('file_with_lines.txt', 'r') as fin:
data = fin.readlines()[3:]
with open('file_with_lines.txt', 'w') as fout:
fout.writelines(data)
Логи с помощью subprocess
Если запускать код в какой-то среде, где лог в файл неудобен а лог с помощью print невозможен, можно использовать echo из bash
import subprocess
text = "Andrei Log: robot/src/libraries/TestController.py is running"
subprocess.run(["echo", text])
Сравнить два файла
Если запускать код в какой-то среде, где лог в файл неудобен а лог с помощью print невозможен, можно использовать echo из bash
import subprocess
def compare(file1, file2):
subprocess.run(["diff", file1, file2])