How to Call an External Command in Python

Learn about the various aspects of the subprocess module.

“I hate quotations. Tell me what you know.” ― Ralph Waldo Emerson, The Essays of Ralph Waldo Emerson

1. Introduction

Do you want to run an external command from inside python? Maybe you want to startup a daemon process (no input or output), or perhaps invoke a command and capture its output?

Python supports several methods for calling an external command. Choice of the method used depends upon whether you want the output from the command, or send it input, or have close control over its lifecycle.

2. Using subprocess.call()

The recommended in python to execute an external command using the facilities provided by the subprocess module. Below, we use the call() function to invoke a simple command.

subprocess.call(['ls', '-l'])
# prints
total 20
-rwxr--r-- 1 xxxxxxx xxxxxxx   36 Jan 26 11:11 readme.txt
...

3. Redirecting STDOUT to a File

How do you redirect the output from the command to a file? Open the file wrapped in a with statement and use the stdout parameter.

with open('joe.txt', 'w') as f:
    subprocess.call(['date'], stdout=f)
# cat joe.txt
Fri Jan 26 06:17:05 UTC 2018

4. Passing Input from STDIN to Command

How can I pass input into STDIN of the child process? Again, using call() you can open the file and pass the handle using the stdin parameter.

with open('readme.txt', 'r') as f:
    subprocess.call(['cat'], stdin=f)
# prints the text in readme.txt
hello world
this is the second line.

5. Executing a Shell Command

Another parameter that can be passed to the call() function is shell=True. This causes the command line to be parsed by the shell.

subprocess.call('cat readme.txt', shell=True)
# prints
hello world
this is the second line.

This, however, is a security risk if the command line comes from an untrusted source such as user input. For example:

cmd = raw_input('enter a command >> ')
# suppose user enters "rm -rf /"
subprocess.call(cmd, shell=True)
# Boom! significant damage to your file system!

6. Exit Code from the Command

What about the exit code from the command? It is returned as the value from the function call().

print 'returncode: ', subprocess.call(['cat', 'jack.txt'])
# prints
cat: jack.txt: No such file or directory
returncode:  1

7. Get More Information Using check_call()

While subprocess.call() allows you to perform quick and easy external command execution, you should use subprocess.check_call() when you need more information in case of command execution errors.

try:
    print subprocess.check_call(['cat', 'jack.txt'])
except subprocess.CalledProcessError as x:
    print 'exception: returncode: {}, command: {}'.format(x.returncode, x.cmd)
# prints
cat: jack.txt: No such file or directory
exception: returncode: 1, command: ['cat', 'jack.txt']

8. Capture Command Output in a String

While we saw how to redirect stdout to a file, what if we want the output from the command as a string? Use subprocess.check_output().

try:
    print subprocess.check_output(raw_input('enter command >> '), shell=True)
except subprocess.CalledProcessError as x:
    print 'exception: returncode: {}, command: {}, output = {}'.format(x.returncode, x.cmd, x.output)
# user enters "date -u" at the prompt
# prints
Fri Jan 26 10:08:08 UTC 2018

Errors are also captured as shown below.

try:
    print subprocess.check_output(raw_input('enter command >> '), shell=True)
except subprocess.CalledProcessError as x:
    print 'exception: returncode: {}, command: {}, output = {}'.format(x.returncode, x.cmd, x.output)
# user enters "ls -l joe" at the prompt
# prints
ls: cannot access joe: No such file or directory
exception: returncode: 2, command: ls -l  joe

Note that using this method, you can also obtain partial output (if any) from the command, even if it fails later on. The following example raises the exception, and returns the partial output in the exception.

try:
    print subprocess.check_output(raw_input('enter command >> '), shell=True)
except subprocess.CalledProcessError as x:
    print 'exception: returncode: {}, command: {}, output = {}'.format(x.returncode, x.cmd, x.output)
# user enters "date -u; exit 1" at the prompt
# prints
exception: returncode: 1, command: date -u; exit 1, output = Fri Jan 26 10:15:39 UTC 2018

Conclusion

We have covered various aspects of using functions in the subprocess module to call external programs from python. Most aspects of the invocation can be controlled including redirecting standard output to file or a string, or arrange for the process to read input from a file.

Leave a Reply

Your email address will not be published. Required fields are marked *