由于自Python 2.6以来命令模块已被弃用,我正在寻找替换commands.getstatusoutput的最佳方法,它返回命令返回码和输出的元组。 subprocess模块相当明显,但它不能直接替代getstatusoutput。在关于getstatusoutput的相关问题中讨论了一个潜在的解决方案 - 但是,我并没有考虑重写原始函数(无论如何还有不到10个LOC),但是想知道是否有更简单的方法。
答案 0 :(得分:10)
没有直接替换,因为commands.getstatusoutput
是一个糟糕的API;它结合了stderr和stdout,没有提供单独检索它们的选项。
您应该使用的便捷API是subprocess.check_output
,因为如果命令失败,它将引发异常。
否则,subprocess
确实没有提供在单个调用中检索输出和状态的方法,但确实存在一些缺陷,但它很容易解决;这是关联问题的答案应该是:
def get_status_output(*args, **kwargs):
p = subprocess.Popen(*args, **kwargs)
stdout, stderr = p.communicate()
return p.returncode, stdout, stderr
如果您想要stdout
和stderr
在一起,请使用stderr=subprocess.STDOUT
。
答案 1 :(得分:7)
getstatusoutput返回(来自python 3.1):)参见:http://docs.python.org/3.3/library/subprocess.html#legacy-shell-invocation-functions
答案 2 :(得分:0)
要回答标题中的问题:这是基于asyncio的getstatusoutput()
实施 - 它是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)
它适用于Windows和Unix。要运行它(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))