subprocess.check_output () dường như không tồn tại (Python 2.6.5)


79

Tôi đã đọc tài liệu Python về mô-đun quy trình con (xem tại đây ) và nó nói về một subprocess.check_output()lệnh có vẻ là chính xác những gì tôi cần.

Tuy nhiên, khi tôi thử và sử dụng nó, tôi gặp lỗi rằng nó không tồn tại và khi tôi chạy dir(subprocess)nó không được liệt kê.

Tôi đang chạy Python 2.6.5 và mã tôi đã sử dụng bên dưới:

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

Có ai có bất kỳ ý tưởng tại sao điều này đang xảy ra?

Câu trả lời:


123

Nó đã được giới thiệu trong 2.7 Xem tài liệu .

Sử dụng quy trình con. Mở nếu bạn muốn đầu ra:

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

14
không giống như check_output, điều này không tăng lên CalledProcessErrorkhi quá trình trả về mã trả về khác 0.
Sridhar Ratnakumar

1
@SridharRatnakumar: tất nhiên vì có sự khác biệt lớn giữa chúng, đó là: chặn và không chặn. Chúng dành cho các trường hợp sử dụng khác nhau!
lpapp

Tôi đẩy nó trong một lambdanhư thế này: check_output = lambda args: Popen(args, stdout = PIPE).communicate()[0]. Chỉ vì tôi đang sử dụng một trình thông dịch tương tác và việc viết ra các định nghĩa hàm đa dòng trong đó là một PITA. Tôi đã sử dụng from subprocess import Popen, PIPEtrước đó trong phiên.
ArtOfWarfare

Làm thế nào để tạo một ping sau đó ?? tôi vẫn có thể sử dụng Popen hay?
TheCrazyProfessor

56

NẾU nó được sử dụng nhiều trong mã bạn muốn chạy nhưng mã đó không phải được duy trì lâu dài (hoặc bạn cần sửa chữa nhanh chóng bất kể các vấn đề về bảo trì tiềm ẩn trong tương lai) thì bạn có thể bỏ qua (hay còn gọi là bản vá khỉ) nó ở bất cứ nơi nào quy trình con được nhập ...

Chỉ cần nâng mã từ 2.7 và chèn nó như vậy ...

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

Có thể phải bồn chồn nhẹ.

Hãy ghi nhớ mặc dù bạn vẫn phải duy trì những backport nhỏ bẩn như thế này. Nếu lỗi được phát hiện và sửa trong bản python mới nhất thì bạn a) phải lưu ý điều đó và b) cập nhật phiên bản của mình nếu bạn muốn giữ an toàn. Ngoài ra, việc ghi đè & tự xác định các chức năng bên trong là cơn ác mộng tồi tệ nhất của anh chàng tiếp theo, đặc biệt là khi anh chàng tiếp theo là BẠN vài năm sau và bạn đã quên tất cả về các vụ hack thú vị mà bạn đã làm lần trước! Tóm lại: hiếm khi là một ý tưởng hay.


2
Tôi đồng tình với phương pháp này. Tôi có thể bao gồm vị trí của nguồn. Bạn có thể tìm thấy nó tại hg.python.org/cpython/file/d37f963394aa/Lib/subprocess.py#l544
Ehtesh Choudhury

1
Lưu ý: CalledProcessError không chấp nhận đầu ra trong python 2.6. (Tôi ngay lập tức bị cắn sau khi sử dụng hack này :(!)
Andy Hayden

cpython hiện đã có trên GitHub - check_outputdành cho Python 2.7 hiện có ở đây: github.com/python/cpython/blob/2.7/Lib/subprocess.py#L194
jamesc 12/09/18

6

Cảm ơn đề xuất bản vá khỉ (và nỗ lực của tôi không thành công - nhưng chúng tôi đã tiêu thụ đầu ra CalledProcessError, vì vậy cần phải vá lỗi đó)

tìm thấy một bản vá 2.6 đang hoạt động tại đây: 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
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.