patternpythonCritical
Running shell command and capturing the output
Viewed 0 times
capturingcommandtheandshellrunningoutput
Problem
I want to write a function that will execute a shell command and return its output as a string, no matter, is it an error or success message. I just want to get the same result that I would have gotten with the command line.
What would be a code example that would do such a thing?
For example:
What would be a code example that would do such a thing?
For example:
def run_command(cmd):
# ??????
print run_command('mysqladmin create test -uroot -pmysqladmin12')
# Should output something like:
# mysqladmin: CREATE DATABASE failed; error: 'Can't create database 'test'; database exists'Solution
In all officially maintained versions of Python, the simplest approach is to use the
The
Modern versions of Python (3.5 or higher):
If you're using Python 3.5+, and do not need backwards compatibility, the new
The return value is a
This can all be compressed to a one-liner if desired:
If you want to pass input to the process's
You can capture errors by passing
Later versions of Python streamline the above further. In Python 3.7+, the above one-liner can be spelled like this:
Using
Older versions of Python (3-3.4): more about
If you are using an older version of Python, or need modest backwards compatibility, you can use the
It takes takes the same arguments as
You can pass
If you need to pipe from
Complex applications and legacy versions of Python (2.6 and below):
If you need deep backwards compatibility, or if you need more sophisticated functionality than
The
To send input and capture output,
```
output = subprocess.Popen(["mycmd", "myarg"],
stdout=subprocess.PIPE).communicate
subprocess.check_output function:>>> subprocess.check_output(['ls', '-l'])
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'check_output runs a single program that takes only arguments as input.1 It returns the result exactly as printed to stdout. If you need to write input to stdin, skip ahead to the run or Popen sections. If you want to execute complex shell commands, see the note on shell=True at the end of this answer.The
check_output function works in all officially maintained versions of Python. But for more recent versions, a more flexible approach is available.Modern versions of Python (3.5 or higher):
runIf you're using Python 3.5+, and do not need backwards compatibility, the new
run function is recommended by the official documentation for most tasks. It provides a very general, high-level API for the subprocess module. To capture the output of a program, pass the subprocess.PIPE flag to the stdout keyword argument. Then access the stdout attribute of the returned CompletedProcess object:>>> import subprocess
>>> result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
>>> result.stdout
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'The return value is a
bytes object, so if you want a proper string, you'll need to decode it. Assuming the called process returns a UTF-8-encoded string:>>> result.stdout.decode('utf-8')
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'This can all be compressed to a one-liner if desired:
>>> subprocess.run(['ls', '-l'], stdout=subprocess.PIPE).stdout.decode('utf-8')
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'If you want to pass input to the process's
stdin, you can pass a bytes object to the input keyword argument:>>> cmd = ['awk', 'length($0) > 5']
>>> ip = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=ip)
>>> result.stdout.decode('utf-8')
'foofoo\n'You can capture errors by passing
stderr=subprocess.PIPE (capture to result.stderr) or stderr=subprocess.STDOUT (capture to result.stdout along with regular output). If you want run to throw an exception when the process returns a nonzero exit code, you can pass check=True. (Or you can check the returncode attribute of result above.) When security is not a concern, you can also run more complex shell commands by passing shell=True as described at the end of this answer.Later versions of Python streamline the above further. In Python 3.7+, the above one-liner can be spelled like this:
>>> subprocess.run(['ls', '-l'], capture_output=True, text=True).stdout
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'Using
run this way adds just a bit of complexity, compared to the old way of doing things. But now you can do almost anything you need to do with the run function alone.Older versions of Python (3-3.4): more about
check_outputIf you are using an older version of Python, or need modest backwards compatibility, you can use the
check_output function as briefly described above. It has been available since Python 2.7.subprocess.check_output(*popenargs, **kwargs)It takes takes the same arguments as
Popen (see below), and returns a string containing the program's output. The beginning of this answer has a more detailed usage example. In Python 3.5+, check_output is equivalent to executing run with check=True and stdout=PIPE, and returning just the stdout attribute.You can pass
stderr=subprocess.STDOUT to ensure that error messages are included in the returned output. When security is not a concern, you can also run more complex shell commands by passing shell=True as described at the end of this answer.If you need to pipe from
stderr or pass input to the process, check_output won't be up to the task. See the Popen examples below in that case.Complex applications and legacy versions of Python (2.6 and below):
PopenIf you need deep backwards compatibility, or if you need more sophisticated functionality than
check_output or run provide, you'll have to work directly with Popen objects, which encapsulate the low-level API for subprocesses.The
Popen constructor accepts either a single command without arguments, or a list containing a command as its first item, followed by any number of arguments, each as a separate item in the list. shlex.split can help parse strings into appropriately formatted lists. Popen objects also accept a host of different arguments for process IO management and low-level configuration.To send input and capture output,
communicate is almost always the preferred method. As in:```
output = subprocess.Popen(["mycmd", "myarg"],
stdout=subprocess.PIPE).communicate
Code Snippets
>>> subprocess.check_output(['ls', '-l'])
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'>>> import subprocess
>>> result = subprocess.run(['ls', '-l'], stdout=subprocess.PIPE)
>>> result.stdout
b'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'>>> result.stdout.decode('utf-8')
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'>>> subprocess.run(['ls', '-l'], stdout=subprocess.PIPE).stdout.decode('utf-8')
'total 0\n-rw-r--r-- 1 memyself staff 0 Mar 14 11:04 files\n'>>> cmd = ['awk', 'length($0) > 5']
>>> ip = 'foo\nfoofoo\n'.encode('utf-8')
>>> result = subprocess.run(cmd, stdout=subprocess.PIPE, input=ip)
>>> result.stdout.decode('utf-8')
'foofoo\n'Context
Stack Overflow Q#4760215, score: 1968
Revisions (0)
No revisions yet.