- How to run Bash commands in Python?
- What is Bash?
- Frequently Asked:
- Method 1 : Using OS module
- os.system()
- os.popen()
- Method 2 : Using subprocess module
- subprocess.call()
- subprocess.Popen()
- Summary
- Related posts:
- subprocess в Python
- Простой пример
- Простой пример Windows
- Bash команда с опциями
- Передать переменную в аргумент команды
- args, returncode, stdout
- Обработка ошибок
- Передача аргументов в скрипт
- Логи с помощью subprocess
- Сравнить два файла
- Определить версию Linux
How to run Bash commands in Python?
Bash commands in Python can be a powerful tool for automating tasks such as setting up development environment and or deploying code to server, and also integrating different tools and languages. So, In this Python article, we will learn to run Bash commands in Python Programming language. But before that a quick introduction about bash and Bash commands.
Table Of Contents
What is Bash?
Bash stands for Bourne-Again Shell which is another example of Shell. Bash is a Unix shell, which is a command-line interface for interacting with an operating system, and it is a popular shell on many Linux and Unix systems.
Here are some examples of common Bash commands:
- ls: List the files in a directory
- cd: Change the current directory
- mkdir: Create a new directory
- cp: Copy a file or directory
- mv: Move a file or directory
- rm: Remove a file or directory
- echo: Print a message to the terminal
Bash also provides a number of powerful features, such as command line editing, command history, and shell scripting, which allow you to automate tasks and customize your shell environment.
Frequently Asked:
Now Lets learn about some methods which can be used to run Bash commands in Python.
Method 1 : Using OS module
We can use some functions of OS module to run Bash commands in Python. OS module comes pre-installed with python programming language and it is the one of the most used module for interaction with system.
os.system()
This os.system() is used to execute commands which is in the string format in Shells of different operating systems by creating a subshell. This method is implemented by using Standard C function system().
– Parameter : This receives a command in string format.
– SYNTAX : os.system(command)
– Return : On Windows, this returns the value returned by the system shell. On UNIX, this returns the exit status of the process.
See the example code below:
import os # this will create a new directory. os.system('mkdir shellfile') # this will list all the subdirectories # in the directory. os.system('ls')
This will create a new directory and then execute the second Bash commands, which will list all the subdirectories in the working directory.
test1.md test2.md test3.md shellfile temp.py
os.popen()
Also we can use another method of os module which is os.popen() . This method opens a pipe of command and this pipe then sends the output to another command.
Here is an example code and output
import os # this will create a directory os in the working directory. os.popen('mkdir os') # this lists all the directories in the working directory. output = os.popen('dir').read() print(output)
test1.md test2.md test3.md os temp.py test4.md
Method 2 : Using subprocess module
Another method which can be used to run Bash commands in Python is by using the subprocess module. The subprocess module comes pre-installed with Python programming language and is mostly used to execute system commands. It has some features which provide edge over the os module like, this connects to input/output/error pipes and obtains their return codes.
subprocess.call()
The subporocess.call() method is used to initiate a program. This method calls/executes the command passed as an argument in the call() function. Here an array of commands can also be passed if you need to provide options and the arguments along with the shell command.
subprocess.call(args, stdin=None,stdout=None,stderr=None,shell=False)
- args : Command that needs to be executed.
- stdin : Standard input stream value which will be passed as os.pipe()
- stdout : Standard output stream value which is obtained.
- stderr : Handles error occurred from standard error stream.
- shell : Boolean, If True executes the program in new shell.
See the example code below:
# importing subprocess module import subprocess # using subprocess to create a new directory using the mkdir command. subprocess.call('mkdir subprocess', shell=True) # listing all the directories. subprocess.call("ls",shell=True)
test1.md test2.md test3.md test4.md subprocess temp.py
subprocess.Popen()
The Popen() function is an upgraded version of call() method of subprocess module which takes a command in string format. This function creates a pope between the calling application and the command which is executed. Popen() function returns the pointer to the stream which is used to read and write to the pipe created by the Popen() function. This function does not wait for the program to be executed.
Below is an example code and output.
# importing subprocess module import subprocess # storing output of Popen() function. output = subprocess.Popen( 'mkdir subprocess', stdout=subprocess.PIPE, stderr=subprocess.STDOUT, shell=True) # Using communicate() function extracting # error and output of Popen function() stdout,stderr = output.communicate() print(stdout) print(stderr) # Print the directories in the working directories subprocess.call('ls',shell=True)
b'' None test1.md test2.md test3.md test4.md subprocess temp.py
In the above code and example you can see by using two functions of subprocess module you can run Bash commands in Python programming language. The Popen() function returns an object which has output and error of the Popen() function in a tuple. The communicate() method can be used to extract output and tuple. As you can see in output there are no errors hence the stderr has returned None.
Summary
In this Python article, How to run Bash commands in Python, we learned about bash and some most used commands of bash. Also we learned about functions and methods through which you can run Bash commands in Python. os.system() and subprocess.call() are for smaller tasks of bash, but the Popen() function of subprocess module and popen() of os module can be used for advanced bash works with output and inputs to other commands because these methods create pipes for I/O. You can always use any of the methods above according to your need.
Make sure to read and write example codes, in order to have a better understanding of this problem. Thanks.
Related posts:
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
Чтобы не выводить результат в терминал а сохранить в переменную, нужно воспользоваться опцией 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
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-30-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())