how to execute a bash command in a python script
Solution 1
@milne's answer works, but subprocess.call()
gives you little feedback.
I prefer to use subprocess.check_output()
so you can analyse what was printed to stdout:
import subprocess
res = subprocess.check_output(["sudo", "apt", "update"])
for line in res.splitlines():
# process the output line by line
check_output
throws an error on on-zero exit of the invoked command
Please note that this doesn't invoke bash
or another shell if you don't specify the shell
keyword argument to the function (the same is true for subprocess.call()
, and you shouldn't if not necessary as it imposes a security hazard), it directly invokes the command.
If you find yourself doing a lot of (different) command invocations from Python, you might want to look at plumbum. With that you can do the (IMO) more readable:
from plumbum.cmd import sudo, apt, echo, cut
res = sudo[apt["update"]]()
chain = echo["hello"] | cut["-c", "2-"]
chain()
Solution 2
It is possible you use the bash as a program, with the parameter -c for execute the commands:
Example:
bashCommand = "sudo apt update"
output = subprocess.check_output(['bash','-c', bashCommand])
Solution 3
The subprocess module is designed to do this:
import subprocess
subprocess.call(["sudo", "apt", "update"])
If you would like the script to terminate if the command fails, you might consider using check_call()
instead of parsing the return code yourself:
subprocess.check_call(["sudo", "apt", "update"])
Solution 4
Also you can use 'os.popen'.
Example:
import os
command = os.popen('ls -al')
print(command.read())
print(command.close())
Output:
total 16
drwxr-xr-x 2 root root 4096 ago 13 21:53 .
drwxr-xr-x 4 root root 4096 ago 13 01:50 ..
-rw-r--r-- 1 root root 1278 ago 13 21:12 bot.py
-rw-r--r-- 1 root root 77 ago 13 21:53 test.py
None
Solution 5
For python 3.5 and more you can use:
import subprocess
try:
result = subprocess.run("sudo apt update", check=True, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
except subprocess.CalledProcessError as err:
raise Exception(str(err.stderr.decode("utf-8")))
except Exception as err:
raise Exception(err)
else:
return result.stdout.decode("utf-8")
Related videos on Youtube
Dremor
Updated on September 18, 2022Comments
-
Dremor over 1 year
How can I launch a bash command with multiple args (for example "
sudo apt update
") from a python script?-
don_crissti about 9 years
-
-
Dremor about 9 yearsthis gave me the following traceback :
Traceback (most recent call last): File "/home/Dremor/test.py", line 3, in <module> subprocess.call('sudo', 'yum', 'update') File "/usr/lib64/python3.4/subprocess.py", line 537, in call with Popen(*popenargs, **kwargs) as p: File "/usr/lib64/python3.4/subprocess.py", line 767, in __init__ raise TypeError("bufsize must be an integer") TypeError: bufsize must be an integer
(I'm using yum as I'm using Fedora as main OS) -
Milind Dumbare about 9 yearsYou forgot the square brackets
-
heemayl about 9 yearsAlso note that
subprocess.call()
is blocking whilesubprocess.Popen()
is non-blocking.. -
alper almost 6 yearsIs it recommended to use (
os.popen
oros.system
), ex:res = os.popen('sudo apt update').read()
? @Anthon -
alper almost 6 yearsI am using long complicated shell commands, hence using under
os.system()
is pretty easy, where I just need to give command line as input string. Why is it not recommend to be used? @Anthon -
Anthon almost 6 yearsIt starts an extra shell just to execute the command, you don't get any feedback from
os.system()
. -
alper almost 6 yearsHow about following example:
os.popen('my_command').read()
which returns an output. But as I understand extra shell consumes additional time. @Anthob -
Anthon almost 6 years@alper Read 0324 python.org/dev/peps/pep-0324. That explains the rationale for making
subprocess
althoughos.system
andos.popen
already existed. Such PEPs are non-trivial to get accepted. Several people have given much more thought to that than you or I ever will. Andsubprocess
has improved since 2003, the others are just still there for backward compatibility. Have you red theos.system
manual page: The subprocess module provides more powerful facilities for spawning new processes and retrieving their results; using that module is preferable to using this function. -
alper over 5 yearsCould I use as with
shell=True
option is it recommended way to use, example:subprocess.check_output('sudo apt update', shell=True).strip().decode('utf-8')
@Anthon -
Anthon over 5 years@alper Yes you could. As I indicated that is a potential security hazard, so I don't know why you think that is recommended. And invoking
sudo
is only going to make that more severe. Maybe using python-apt is a better solution (I have not looked into that myself). -
alper over 5 yearsI will use it without providing
sudo
for general commands. I have to use|
(pipe) on my commands, which I cannot able to use it viasubprocess.run()
. For example command(echo hello | cut -c 2-
) =>res = subprocess.check_output(["echo", "hello", "|", "cut -c 2-"])
does not see|
. If you could extend your answer for pipe|
usage undersubprocess
that will be so helpful. -
Anthon over 5 years@alper in that case take a serious look at plumbum, it is worth getting up to speed with that.
-
alper over 5 years
subprocess.check_output()
returns byte stream (b''
), I guess we need to add.decode('utf-8').strip()
to end ofsubprocess.check_output(["sudo", "apt", "update"])
to convert it into character stream. Instead of doing this additional conversion, could we usesubprocess.Popen
withuniversal_newlines=True
flag:res = subprocess.Popen(['sudo', 'apt', 'update'], stdout=subprocess.PIPE, universal_newlines=True).communicate()[0].strip()
to increase its speed? -
Anthon over 5 years@alper If you are on Python3 you need to do that, on Python2 you don't. Please don't use the commenting here as a chat system. If you have a question post it as such.
-
alper over 5 yearsWhat do you mean by "blocking"? @heemayl
-
aquagremlin about 5 yearswhy am i getting an error when i use it
-
aquagremlin about 5 yearssubprocess.check_call(["sudo", "apt", "update"])
-
aquagremlin about 5 yearsCalledProcessError Traceback (most recent call last) <ipython-input-21-33ce645708e7> in <module>() ----> 1 subprocess.check_call(["sudo", "apt", "update"]) /usr/lib/python2.7/subprocess.pyc in check_call(*popenargs, **kwargs) 188 if cmd is None: 189 cmd = popenargs[0] --> 190 raise CalledProcessError(retcode, cmd) 191 return 0 192 CalledProcessError: Command '['sudo', 'apt', 'update']' returned non-zero exit status 1
-
aquagremlin about 5 yearsthis error only happens when i run it in a jupyter notebook
-
aquagremlin about 5 yearsmaybe i'll start a new question since this is ot