Each Answer to this Q is separated by one/two green lines.
How can I get the output of a process run using
StringIO.StringIO object to
stdout gives this error:
Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 444, in call return Popen(*popenargs, **kwargs).wait() File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 588, in __init__ errread, errwrite) = self._get_handles(stdin, stdout, stderr) File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 945, in _get_handles c2pwrite = stdout.fileno() AttributeError: StringIO instance has no attribute 'fileno' >>>
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", "22.214.171.124"])
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.
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
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.
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)
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.
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.
The key is to use the function
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")
In : import subprocess In : s=subprocess.check_output(["echo", "Hello World!"]) In : s Out: 'Hello World!\n'
Based on sargue’s answer. Credit to sargue.