how to execute a bash command in a python script
@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_outputthrows an error on on-zero exit of the invoked command
Please note that this doesn't invoke
bashor another shell if you don't specify the
shellkeyword 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()
Is it recommended to use (`os.popen` or `os.system`), ex: `res = os.popen('sudo apt update').read()`? @Anthon
I 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
It starts an extra shell just to execute the command, you don't get any feedback from `os.system()`.
How about following example: `os.popen('my_command').read()` which returns an output. But as I understand extra shell consumes additional time. @Anthob
@alper Read 0324 https://www.python.org/dev/peps/pep-0324/. That explains the rationale for making `subprocess` although `os.system` and `os.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. And `subprocess` has improved since 2003, the others are just still there for backward compatibility. Have you red the `os.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.*
Could 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
@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).
I will use it without providing `sudo` for general commands. I have to use `|` (pipe) on my commands, which I cannot able to use it via `subprocess.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 under `subprocess ` that will be so helpful.
@alper in that case take a serious look at plumbum, it is worth getting up to speed with that.
`subprocess.check_output()` returns byte stream (`b''`), I guess we need to add `.decode('utf-8').strip()` to end of `subprocess.check_output(["sudo", "apt", "update"])` to convert it into character stream. Instead of doing this additional conversion, could we use `subprocess.Popen` with `universal_newlines=True` flag: `res = subprocess.Popen(['sudo', 'apt', 'update'], stdout=subprocess.PIPE, universal_newlines=True).communicate().strip()` to increase its speed?