subprocess.check_output()似乎不存在(Python 2.6.5)


79

我一直在阅读有关子流程模块的Python文档(请参阅此处),它讨论的subprocess.check_output()命令似乎正是我所需要的。

但是,当我尝试使用它时,出现错误,提示它不存在,并且在运行dir(subprocess)时未列出。

我正在运行Python 2.6.5,下面使用的代码是:

import subprocess
subprocess.check_output(["ls", "-l", "/dev/null"])

有谁知道为什么会这样吗?

Answers:


123

它是在2.7的见介绍文档

如果需要输出,请使用subprocess.Popen

>>> import subprocess
>>> output = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE).communicate()[0]

14
与check_output不同,CalledProcessError当进程返回非零返回码时,此值不会提高。
Sridhar Ratnakumar 2012年

1
@SridharRatnakumar:当然是因为它们之间有很大的区别,即:阻塞和非阻塞。它们用于不同的用例!
lpapp 2013年

我猛的一个lambda是这样的:check_output = lambda args: Popen(args, stdout = PIPE).communicate()[0]。仅仅因为我在交互式解释器中,并且在其中编写多行函数defs是一种PITA。我from subprocess import Popen, PIPE在会话的早期使用过。
ArtOfWarfare

那么如何进行ping?我仍然可以使用Popen还是?
TheCrazyProfessor

56

如果要在您要运行的代码中大量使用该代码,但是不必长期维护该代码(或者,无论将来有什么麻烦,您都需要快速修复),那么您可以避开麻烦(aka猴子补丁)在子程序导入的任何地方...

只需从2.7提升代码并插入即可...

import subprocess

if "check_output" not in dir( subprocess ): # duck punch it in!
    def f(*popenargs, **kwargs):
        if 'stdout' in kwargs:
            raise ValueError('stdout argument not allowed, it will be overridden.')
        process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
        output, unused_err = process.communicate()
        retcode = process.poll()
        if retcode:
            cmd = kwargs.get("args")
            if cmd is None:
                cmd = popenargs[0]
            raise subprocess.CalledProcessError(retcode, cmd)
        return output
    subprocess.check_output = f

可能需要轻微的坐立不安。

请记住,尽管您有责任维持这样肮脏的小后路。如果在最新的python中发现并纠正了错误,那么您a)必须注意该问题,以及b)如果要保持安全性,请更新您的版本。此外,自己改写和定义内部功能是下一个家伙最糟糕的噩梦,尤其是当下一个家伙是你几年前的下一个,而你却忘记了上一次所做的肮脏的骇客时!总结:这很少是一个好主意。


2
我同意这种方法。我可能会包括来源的位置。您可以在hg.python.org/cpython/file/d37f963394aa/Lib/subprocess.py#l544
Ehtesh Choudhury

1
注意:CalledProcessError不接受python 2.6中的输出。(使用此技巧后,我立即被咬了!:()
Andy Hayden 2014年

cpython现在在GitHub上-check_output用于Python 2.7的当前位置在这里:github.com/python/cpython/blob/2.7/Lib/subprocess.py#L194
jamesc

6

多亏了猴子补丁的建议(而且我的尝试失败了-但我们正在使用CalledProcessError输出,因此需要猴子补丁)

在此处找到了有效的2.6补丁:http : //pydoc.net/Python/pep8radius/0.9.0/pep8radius.shell/

"""Note: We also monkey-patch subprocess for python 2.6 to
give feature parity with later versions.
"""
try:
    from subprocess import STDOUT, check_output, CalledProcessError
except ImportError:  # pragma: no cover
    # python 2.6 doesn't include check_output
    # monkey patch it in!
    import subprocess
    STDOUT = subprocess.STDOUT

    def check_output(*popenargs, **kwargs):
        if 'stdout' in kwargs:  # pragma: no cover
            raise ValueError('stdout argument not allowed, '
                             'it will be overridden.')
        process = subprocess.Popen(stdout=subprocess.PIPE,
                                   *popenargs, **kwargs)
        output, _ = process.communicate()
        retcode = process.poll()
        if retcode:
            cmd = kwargs.get("args")
            if cmd is None:
                cmd = popenargs[0]
            raise subprocess.CalledProcessError(retcode, cmd,
                                                output=output)
        return output
    subprocess.check_output = check_output

    # overwrite CalledProcessError due to `output`
    # keyword not being available (in 2.6)
    class CalledProcessError(Exception):

        def __init__(self, returncode, cmd, output=None):
            self.returncode = returncode
            self.cmd = cmd
            self.output = output

        def __str__(self):
            return "Command '%s' returned non-zero exit status %d" % (
                self.cmd, self.returncode)
    subprocess.CalledProcessError = CalledProcessError
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.