Python Running System Command

So there are a few ways to run system command using python, but I tend to find the below approach the easiest to use and has error handling.

First off I would create a function rather than running the commands over and over:

import subprocess

def run(command):
    '''takes a string command and hands back a subprocess object'''
    process = subprocess.Popen(command.split(), shell=False, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    process.wait()
    return process

The function itself is pretty small and makes use of the subprocess library .

Popen takes a list which is each part of your command, for example the command ls -lt file would be written as:

['ls', '-lt', 'file']

This however is avoided by using the split method on our function input.

Once we have our function loaded the usage is pretty easy:

>>> c = run('pwd')
>>> c
< subprocess.Popen object at 0x1004a3c50>

Like mentioned above Popen returns a subprocess object, not the result of your command. To access the results and other useful information we are just a method away:

>>> c.communicate()
('/Users/nessy\n', '')

The real beauty I find in using this approach is error handling, something os.system doesn’t provide. Using our object we can check the returncode and validate everything ran cleanly:

>>> c.returncode
0

A return code of 0 is telling us an error was not returned, but what would happen if something did happen:

>>> c = run('ls -ld not_a_file_here.txt')
>>>
>>> c.communicate()
('', 'ls: not_a_file_here.txt: No such file or directory\n')
>>>
>>> c.returncode
1

A return code greater than 0 tells us something went wrong.

Lets see that same command work properly:

>>> c = run('ls -ld Desktop')
>>>
>>> c.communicate()
('drwx------+ 42 nessy  staff  1428 Nov  9 10:35 Desktop\n', '')
>>>
>>> c.returncode
0

Now isn’t that slick!

Using this approach you may want to write blocks of commands something like this:

command = 'ls -ld not_a_file_here.txt'
try:
    c = run(command)
except OSError as e:
    raise(e)

if c.returncode > 0:
    print 'Error: we received a return code of %s' % c.returncode
else:
    print c.communicate()