subprocess.check_output ()이 존재하지 않는 것 같습니다 (Python 2.6.5)


79

나는 subprocess 모듈에 관한 파이썬 문서를 읽고 있었는데 ( 여기를보세요 ) subprocess.check_output()정확히 내가 필요한 것처럼 보이는 명령 에 대해 이야기 합니다.

그러나 그것을 시도하고 사용하면 존재하지 않는다는 오류가 발생하고 실행 dir(subprocess)하면 나열되지 않습니다.

Python 2.6.5를 실행하고 있으며 사용한 코드는 다음과 같습니다.

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

왜 이런 일이 일어나는지 아는 사람이 있습니까?

답변:


123

2.7에서 도입되었습니다 . 문서를 참조하십시오 .

출력을 원하면 subprocess.Popen을 사용하십시오 .

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

14
check_output과 달리 CalledProcessError프로세스가 0이 아닌 반환 코드를 반환 할 때 발생 하지 않습니다 .
Sridhar Ratnakumar 2011

1
@SridharRatnakumar : 물론 그들 사이에는 큰 차이가 있기 때문입니다. 즉, 차단과 비 차단입니다. 다양한 사용 사례를위한 것입니다!
lpapp

나는 lambda이것을 다음과 같이 밀어 넣었다 : check_output = lambda args: Popen(args, stdout = PIPE).communicate()[0]. 내가 인터랙티브 인터프리터에 있기 때문에 여러 줄 함수 정의를 작성하는 것이 일종의 PITA입니다. from subprocess import Popen, PIPE세션 초반에 사용 했습니다.
ArtOfWarfare

그럼 핑을 만드는 방법 ?? 여전히 Popen을 사용할 수 있습니까?
TheCrazyProfessor

56

경우 당신이 실행하려는 코드를 많이 사용하지만 사용자들은 코드가 장기적으로 유지 될 필요가 없다 (또는 미래에 관계없이 잠재적 인 유지 보수 두통의 빠른 수정이 필요) 다음 수 오리 펀치 (원숭이 패치 일명) 하위 프로세스를 가져올 때마다 ...

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

약간의 안절부절이 필요할 수 있습니다.

이와 같이 더럽고 작은 백 포트를 유지해야 할 책임이 있음을 명심하십시오. 최신 파이썬에서 버그가 발견되고 수정되면 a)이를인지하고 b) 보안을 유지하려면 버전을 업데이트해야합니다. 또한 내부 함수를 직접 재정의하고 정의하는 것은 다음 사람에게 최악의 악몽입니다. ​​특히 다음 사람이 몇 년 후 당신이고 지난번에했던 그 로디 해킹에 대해 모두 잊어 버린 경우! 요약하면 아주 드물게 좋은 생각입니다.


2
이 방법에 동의합니다. 나는 아마도 출처의 위치를 ​​포함 할 것입니다. 당신은 그것을 찾을 수 있습니다 hg.python.org/cpython/file/d37f963394aa/Lib/subprocess.py#l544
Ehtesh Choudhury의에게

1
참고 : CalledProcessError는 Python 2.6에서 출력을 허용하지 않습니다. (나는 즉시이 해킹을 사용 후 물린있어 :(!)
앤디 헤이든

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.