How can I get the output of a process run using subprocess.call()?

Passing a StringIO.StringIO object to stdout gives this error:

Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/Frameworks/", line 444, in call return Popen(*popenargs, **kwargs).wait() File "/Library/Frameworks/", line 588, in __init__ errread, errwrite) = self._get_handles(stdin, stdout, stderr) File "/Library/Frameworks/", line 945, in _get_handles c2pwrite = stdout.fileno() AttributeError: StringIO instance has no attribute 'fileno' >>> 
4

7 Answers

If you have Python version >= 2.7, you can use subprocess.check_output which basically does exactly what you want (it returns standard output as string).

Simple example (linux version, see note):

import subprocess print subprocess.check_output(["ping", "-c", "1", "8.8.8.8"]) 

Note that the ping command is using linux notation (-c for count). If you try this on Windows remember to change it to -n for same result.

As commented below you can find a more detailed explanation in this other answer.

8

Output from subprocess.call() should only be redirected to files.

You should use subprocess.Popen() instead. Then you can pass subprocess.PIPE for the stderr, stdout, and/or stdin parameters and read from the pipes by using the communicate() method:

from subprocess import Popen, PIPE p = Popen(['program', 'arg1'], stdin=PIPE, stdout=PIPE, stderr=PIPE) output, err = p.communicate(b"input data that is passed to subprocess' stdin") rc = p.returncode 

The reasoning is that the file-like object used by subprocess.call() must have a real file descriptor, and thus implement the fileno() method. Just using any file-like object won't do the trick.

See here for more info.

10

For python 3.5+ it is recommended that you use the run function from the subprocess module. This returns a CompletedProcess object, from which you can easily obtain the output as well as return code.

from subprocess import PIPE, run command = ['echo', 'hello'] result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True) print(result.returncode, result.stdout, result.stderr) 
4

I have the following solution. It captures the exit code, the stdout, and the stderr too of the executed external command:

import shlex from subprocess import Popen, PIPE def get_exitcode_stdout_stderr(cmd): """ Execute the external command and get its exitcode, stdout and stderr. """ args = shlex.split(cmd) proc = Popen(args, stdout=PIPE, stderr=PIPE) out, err = proc.communicate() exitcode = proc.returncode # return exitcode, out, err cmd = "..." # arbitrary external command, e.g. "python mytest.py" exitcode, out, err = get_exitcode_stdout_stderr(cmd) 

I also have a blog post on it here.

Edit: the solution was updated to a newer one that doesn't need to write to temp. files.

6

I recently just figured out how to do this, and here's some example code from a current project of mine:

#Getting the random picture. #First find all pictures: import shlex, subprocess cmd = 'find ../Pictures/ -regex ".*\(JPG\|NEF\|jpg\)" ' #cmd = raw_input("shell:") args = shlex.split(cmd) output,error = subprocess.Popen(args,stdout = subprocess.PIPE, stderr= subprocess.PIPE).communicate() #Another way to get output #output = subprocess.Popen(args,stdout = subprocess.PIPE).stdout ber = raw_input("search complete, display results?") print output #... and on to the selection process ... 

You now have the output of the command stored in the variable "output". "stdout = subprocess.PIPE" tells the class to create a file object named 'stdout' from within Popen. The communicate() method, from what I can tell, just acts as a convenient way to return a tuple of the output and the errors from the process you've run. Also, the process is run when instantiating Popen.

1

The key is to use the function subprocess.check_output

For example, the following function captures stdout and stderr of the process and returns that as well as whether or not the call succeeded. It is Python 2 and 3 compatible:

from subprocess import check_output, CalledProcessError, STDOUT def system_call(command): """ params: command: list of strings, ex. `["ls", "-l"]` returns: output, success """ try: output = check_output(command, stderr=STDOUT).decode() success = True except CalledProcessError as e: output = e.output.decode() success = False return output, success output, success = system_call(["ls", "-l"]) 

If you want to pass commands as strings rather than arrays, use this version:

from subprocess import check_output, CalledProcessError, STDOUT import shlex def system_call(command): """ params: command: string, ex. `"ls -l"` returns: output, success """ command = shlex.split(command) try: output = check_output(command, stderr=STDOUT).decode() success = True except CalledProcessError as e: output = e.output.decode() success = False return output, success output, success = system_call("ls -l") 
3

In Ipython shell:

In [8]: import subprocess In [9]: s=subprocess.check_output(["echo", "Hello World!"]) In [10]: s Out[10]: 'Hello World!\n' 

Based on sargue's answer. Credit to sargue.

2