Monday, 26 December 2016

[Python] thôi dùng subprocess.check_output

Function tiện tay subprocess.check_output rất hấp dẫn khiến người ta khó có thể từ chối dùng nó. Để kiểm tra output một câu lệnh, chỉ cần:
In [1]: import subprocess as spr

In [2]: output = spr.check_output(['ls', '/etc/hosts'])

In [3]: print(output)
b'/etc/hosts\n'
Chuyện này không có gì sai cho đến khi có gì đó sai sai xảy ra.

Nếu có lỗi xảy ra, ta chỉ nhận được một exception chứ không thu được phần lỗi của câu lệnh (stderr):

In [4]: output = spr.check_output(['ls', '/etc/hostx'])
ls: /etc/hostx: No such file or directory
---------------------------------------------------------------------------
CalledProcessError                        Traceback (most recent call last)
<ipython-input-4-f0a05e894c99> in <module>()
----> 1 output = spr.check_output(['ls', '/etc/hostx'])

/usr/local/lib/python3.5/subprocess.py in check_output(timeout, *popenargs, **kwargs)
    627
    628     return run(*popenargs, stdout=PIPE, timeout=timeout, check=True,
--> 629                **kwargs).stdout
    630
    631

/usr/local/lib/python3.5/subprocess.py in run(input, timeout, check, *popenargs, **kwargs)
    709         if check and retcode:
    710             raise CalledProcessError(retcode, process.args,
--> 711                                      output=stdout, stderr=stderr)
    712     return CompletedProcess(process.args, retcode, stdout, stderr)
    713

CalledProcessError: Command '['ls', '/etc/hostx']' returned non-zero exit status 1

Bỏ qua error luôn là nguồn gốc của đau thương, hãy dùng Popen để thu được cả stdout lẫn stderr:
In [8]: p = spr.Popen(['ls', '/etc/hostx'], stdout=spr.PIPE, stderr=spr.PIPE)

In [9]: stdout, stderr = p.communicate()

In [10]: print(stdout, stderr, p.returncode)
b'' b'ls: /etc/hostx: No such file or directory\n' 1
Nếu đã quen dùng check_ouput, hãy thay đổi thói quen, vì một thế giới ít bug hơn 😲

Bài viết thực hiện trên Python:
In [7]: import sys; print(sys.version)
3.5.1 (default, Apr 21 2016, 17:24:52)
[GCC 4.2.1 Compatible Apple LLVM 5.1 (clang-503.0.40)]

Hết.
HVN at http://www.familug.org/ and http://pymi.vn