Python: execute shell commands (and get the output) with the os package
This article is part of a two-part series related to running shell commands from within Python.
Execute shell commands using the os package
The most straightforward solution to running shell commands via Python is simply by using the system method of the os package. The os package “provides a portable way of using operating system dependent functionality.” The system method executes a string as a command in a subshell, which basically is an independent instance of the command processor of your operating system. For Windows, commands will be run using cmd.exe, for Linux this will be Bash, Mac will use Bash or Z shell.
The following code will open a subshell, run the command, and return the process exit code — a 0 (zero) if the command has run successfully, other numbers mean something has gone wrong (see Linux and Windows).
import os os.system('echo "Hello World!"')
Execute shell commands and get the output using the os package
Sometimes, you’re not only interested in running shell commands, but you’d also like to know what printed output is. The os package also has a solution for this: the popen method. This method opens a pipe into the command, which is used to transfer its output to a Python variable.
The following code will once again open a subshell and run the command, but instead of returning the process exit code, it will return the command output. If you ‘d like to remove the trailing nextline (\n), you can use the strip method
output_stream = os.popen('echo "Hello World!"') output_stream.read()
- If the command passed to the shell generates errors, it will only return two single quotes.
- If you would like to know if a command completed successfully, you can access the process exit code using the close method. Like this:
output_stream = os.popen('non-existing-command') output_stream.close()
The popen method of the os package uses the subprocess module. So instead of using popen, you might as well interface with the subprocess module directly. We discuss this in the next article.
Our Blog
When I launch a long running unix process within a python script, it waits until the process is finished, and only then do I get the complete output of my program. This is annoying if I’m running a process that takes a while to finish. And I want to capture the output and display it in the nice manner with clear formatting.
Using the subprocess and shlex library
Python has a “batteries included” philosophy. I have used 2 standard libraries to solve this problem.
import subprocess import shlex
- subprocess—Works with additional processes.
- shlex—Lexical analysis of shell-style syntaxes.
subprocess.popen
To run a process and read all of its output, set the stdout value to PIPE and call communicate().
import subprocess process = subprocess.Popen(['echo', '"Hello stdout"'], stdout=subprocess.PIPE) stdout = process.communicate()[0] print 'STDOUT:<>'.format(stdout)
The above script will wait for the process to complete and then it will display the output. So now we are going to read the stdout line by line and display it in the console untill it completes the process.
output = process.stdout.readline()
This will read a line from the stdout.
The poll() method will return
while True: output = process.stdout.readline() if output == '' and process.poll() is not None: break if output: print output.strip() rc = process.poll()
The above will loop and keep on reading the stdout and check for the return code and displays the output in real time.
I had one more problem in parsing the shell commands to pass it to popen when I set the shell=False. Below is an example command:
rsync -avzXH --delete --exclude=*.swp --exclude=**/drivers.ini /media/lgisos/lg.iso root@42-a:/isodevice
To split the string using shell-like syntax I have used shlex library’s split method.
Here is the final code looks like
def run_command(command): process = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE) while True: output = process.stdout.readline() if output == '' and process.poll() is not None: break if output: print output.strip() rc = process.poll() return rc