在Python 3中替换getstatusoutput

时间:2012-07-05 12:40:33

标签: python-3.x python

由于自Python 2.6以来命令模块已被弃用,我正在寻找替换commands.getstatusoutput的最佳方法,它返回命令返回码和输出的元组。 subprocess模块相当明显,但它不能直接替代getstatusoutput。在关于getstatusoutput的相关问题中讨论了一个潜在的解决方案 - 但是,我并没有考虑重写原始函数(无论如何还有不到10个LOC),但是想知道是否有更简单的方法。

3 个答案:

答案 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

如果您想要stdoutstderr在一起,请使用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))