iMind Developers Blog

iMind開発者ブログ

Pythonのsubprocessで標準出力を取得

概要

Pythonで外部コマンドを呼んで標準出力を文字列で取得する。

バージョン情報

  • Python 3.6.8

事前準備

標準出力と標準エラーに出力する下記のようなコード(out.py)を用意しておく。

import sys

print('standard out')
print('standard error', file=sys.stderr)

check_output

check_outputを使うと戻り値に標準出力の結果が返る。

import subprocess
subprocess.check_output(['python', 'out.py'])
    #=> b'standard out\n'

上記ではstdoutの方だけbytesで結果が返っている。stderrorの方は戻り値には入らない。

stderrの出力先を標準出力に向けると双方の結果が返る。

subprocess.check_output(['python', 'out.py'], stderr=subprocess.STDOUT)
    #=> b'standard error\nstandard out\n'

Popen.communicate

Popen.communicateを使うとより細かくプロセスの制御ができる。

例えば out.py の最後にexit(1)を追加した out2.py というコードを用意した場合。

import sys
print('standard out')
print('standard error', file=sys.stderr)

sys.exit(1)

check_outputでは実行したコードがexit status 0以外を返した場合、CalledProcessErrorがraiseされる。

subprocess.check_output(['python', 'out2.py'])

実行結果

CalledProcessError: Command '['python', 'out2.py']' returned non-zero exit status 1.

これをPopenで開けると、exit statusが0以外でも標準出力の結果が取れる。

proc = subprocess.Popen(['python', 'out2.py'], stdout=subprocess.PIPE)

proc.communicate()
    #=> (b'standard out\n', None)

proc.returncode
    #=> 1

communicate() の戻り値は要素が2つのtupleになっている。左が標準出力、右が標準エラー。

エラーの中身も取る場合は stderr=subprocess.PIPE を指定する。

proc = subprocess.Popen(['python', 'out2.py'],
        stdout=subprocess.PIPE,
        stderr=subprocess.PIPE)

proc.communicate()
    #=> (b'standard out\n', b'standard error\n')

コマンドの標準出力を行ごとに取得

Popenに対してcommunicateせずにstdoutを取得することで下記のように行ごとに標準出力を取得可能。

proc = subprocess.Popen(['cat', 'foo.txt'], stdout=subprocess.PIPE)
for line in proc.stdout:
    print(line)

標準エラーを捨てたい場合

check_outputもPopenもエラーは何も指定しないと標準エラーとしてスクリプト実行時に画面に出力される。

これらを表示せずに捨てたい場合は subprocess.DEVNULL を指定する。

check_outputの場合。

subprocess.check_output(['python', 'out.py'],
        stderr=subprocess.DEVNULL)

Popenの場合。

proc = subprocess.Popen(['python', 'out2.py'],
        stdout=subprocess.PIPE,
        stderr=subprocess.DEVNULL)
proc.communicate()

改定履歴

Author: Masato Watanabe, Date: 2019-02-17, 記事投稿