Since the commands module is deprecated since Python 2.6, I'm looking into the best way to replace commands.getstatusoutput which returns a tuple of the command's return code and output. The subprocess module is rather obvious, however, it doesn't offer a direct replacement for getstatusoutput. A potential solution is discussed in a related question concerning getstatusoutput - however, I'm not looking into rewriting the original function (which has less then 10 LOC anyway) but would like to know if there is a more straightforward way.
-
Did you read the answer to that question? The Pythonic solution is to use `Popen.communicate`, then read the `Popen.statuscode`. That will give you the stdout and stderr in separate strings, though. – Fred Foo Jul 05 '12 at 12:47
-
1Yes, but as I said, I'm not looking into rewriting the commands module's function. What the original function does is to simply use os.popen, then read and close the pipe. That's what the suggested new version does as well (once fixed w/ what's written in the answer). However, I was hoping for anything resembling that function in the standard library w/out having to maintain my own replacement. – Gerald Senarclens de Grancy Jul 05 '12 at 13:08
3 Answers
There is no direct replacement, because commands.getstatusoutput
was a bad API; it combines stderr and stdout without giving an option to retrieve them separately.
The convenience API that you should be using is subprocess.check_output
as it will throw an exception if the command fails.
Otherwise, it does appear somewhat of a deficiency that subprocess
doesn't provide a method to retrieve output and status in a single call, but it's easy to work around; here's what the answer to the linked question should have been:
def get_status_output(*args, **kwargs):
p = subprocess.Popen(*args, **kwargs)
stdout, stderr = p.communicate()
return p.returncode, stdout, stderr
If you want stdout
and stderr
together, use stderr=subprocess.STDOUT
.

- 152,476
- 27
- 293
- 366
-
Thanks for your answer, it basically told me what I needed to know. Just a hint: "communicate() returns a tuple (stdout, stderr)" – Gerald Senarclens de Grancy Jul 09 '12 at 09:37
getstatusoutput is back (from python 3.1) :) See: http://docs.python.org/3.3/library/subprocess.html#legacy-shell-invocation-functions

- 2,165
- 1
- 16
- 19
-
-
@radtek `import subprocess;subprocess.getstatusoutput("echo a")` still works for me (Python 3.6.4 | Anaconda). – Liso Jan 31 '18 at 08:29
-
The question was about `import commands` as in `commands.getstatusoutput`, that's gone. – radtek Jan 31 '18 at 14:00
To answer the question from the title: here's asyncio-based getstatusoutput()
implementation -- it is code example from the docs that is modified to follow more closely subprocess.getstatusoutput()
interface:
import asyncio
import locale
from asyncio.subprocess import PIPE, STDOUT
@asyncio.coroutine
def getstatusoutput(cmd):
proc = yield from asyncio.create_subprocess_shell(cmd,
stdout=PIPE, stderr=STDOUT)
try:
stdout, _ = yield from proc.communicate()
except:
try:
proc.kill()
except ProcessLookupError: # process is already dead
pass
raise
finally:
exitcode = yield from proc.wait()
# return text
output = stdout.decode(locale.getpreferredencoding(False))
# universal newlines mode
output = output.replace("\r\n", "\n").replace("\r", "\n")
if output[-1:] == "\n": # remove a trailing newline
output = output[:-1]
return (exitcode, output)
It works both Windows and Unix. To run it (from the same example):
import os
from contextlib import closing
if os.name == 'nt': # Windows
loop = asyncio.ProactorEventLoop()
asyncio.set_event_loop(loop)
else:
loop = asyncio.get_event_loop()
with closing(loop):
coro = getstatusoutput('python -m platform')
exitcode, stdout = loop.run_until_complete(coro)
if exitcode == 0:
print("Platform:", stdout)
else:
print("Python failed with exit code %s: %s" % (exitcode, stdout))

- 399,953
- 195
- 994
- 1,670