Python linux subprocess call

subprocess в Python

Изображение баннера

В этой статье вы узнаете как выполнять команды Linux и Windows из кода на Python 3.

Создайте файл subprocess_lesson.py и копируйте туда код из примеров.

Запустить скрипт можно командой

Простой пример

Пример программы, которая выполняет Linux команду ls

import subprocess subprocess.run( ‘ls’ )

Простой пример Windows

Пример программы, которая выполняет в Windows команду dir

import subprocess subprocess.run(‘dir’, shell = True )

У меня пока что не работает

Bash команда с опциями

Чтобы выполнить 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])

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)

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

Читайте также:  Ssh linux настройка centos

Чтобы не выводить результат в терминал а сохранить в переменную, нужно воспользоваться опцией capture_output = True — доступна, начиная с версии Python 3.7

import subprocess p1 = subprocess.run([ ‘ls’ , ‘-la’ ], capture_output = True ) print(p1.stdout)

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())

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)

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 в этом примере не выдаёт никаких ошибок

Чтобы Python информировал об ошибках во внешних командах используйте опцию check = True

Читайте также:  Автозапуск через cron linux

import subprocess p1 = subprocess.run([ ‘ls’ , ‘-la’ , ‘not_exist’], capture_output = True , text=True, check = True ) print(p1.returncode) print(p1.stderr)

Traceback (most recent call last): File «subprocess_lesson.py», line 3, in 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)

Передача аргументов в скрипт

Допустим, нужно вызвать скрипт с несколькими аргументами

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 2023-07-15-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])

Определить версию Linux

С помощью subprocess можно в том числе определить версию Linux

import subprocess import sys CENTOS = < "os_name" : "CentOS" , "cmd" : "rpm --eval %" > REDHAT = < "os_name" : "Red" , "cmd" : "rpm --eval %" > ROCKY = < "os_name" : "Rocky" , "cmd" : "rpm --eval %" > UBUNTU = < "os_name" : "Ubuntu" , "cmd" : "cat /etc/issue" >OS_LIST = [CENTOS, REDHAT, ROCKY, UBUNTU] def find_os () -> object : try : p = subprocess.run([ «lsb_release» , «-a» ], capture_output= True , text= True ) except Exception as e: print (f «lsb_release -a call failed: » , file =sys.stderr) raise system_release = str (p.stdout) + str (p.stderr) system_release = system_release.split() for os in OS_LIST: name = os[ «os_name» ] if name in system_release: break else : os = None return os def get_name (os) -> str : name = os[ «os_name» ] return name def get_version (os) -> str : cmd = os[ «cmd» ] cmd = cmd.split() p = subprocess.run(cmd, capture_output= True , text= True ) version = str (p.stdout) try : version = int (version) except : version = version.split() version = version[ 1 ] return version def get_linux_version () -> tuple : os = find_os() if os is not None : name = get_name(os) version = get_version(os) linux_version = (name, version) else : print ( «os is not found» ) linux_version = ( None , None ) return linux_version if __name__ == ‘__main__’ : print (get_linux_version())

Читайте также:  Linux mint режим планшета

Источник

Оцените статью
Adblock
detector