Edited at

[Python2.7] subprocess の使い方まとめ

More than 1 year has passed since last update.


概要

subprocessを使う機会が結構多いので、わからなくて調べた点をまとめます。

調査時の自分のユースケースとしてPython 2.7環境が前提だったため、本記事はPython 2.7向けになります。

基本的には以下の公式ドキュメントを参照して下さい。

17.1. subprocess — サブプロセス管理 — Python 2.7.x ドキュメント

特にPython3.5以上の場合は汎用のrun()コマンドが追加されていたりと使用方法が異なっているため、

そのまま転用せず公式を参照して下さい。

17.5. subprocess — サブプロセス管理 — Python 3.5.2 ドキュメント


インポート指定


import

import subprocess



基本的なAPI


subprocess.call

・実行時の標準出力/標準エラーは実行されたタイミングで出力される

・正常時も異常時もリターンコードを返す


実行サンプル

import subprocess

print '!!! start'

cmd = 'echo aaa'
retcode = subprocess.call(cmd.split())
print retcode

cmd = 'false'
retcode = subprocess.call(cmd.split())
print retcode

print '!!! end'



出力

aaa

!!! start
0
1
!!! end


subprocess.check_call

・実行時の標準出力/標準エラーは実行されたタイミングで出力される

・正常時にはリターンコード0を返す

・異常時には subprocess.CalledProcessError 例外を送出する


実行サンプル

import subprocess

print '!!! start'

cmd = 'echo aaa'
retcode = subprocess.check_call(cmd.split())
print retcode

cmd = 'false'
try:
retcode = subprocess.check_call(cmd.split())
except subprocess.CalledProcessError as e:
print e.returncode
print e.cmd
print e.output

print '!!! end'



出力

aaa

!!! start
0
1
['false']
None
!!! end


subprocess.check_output

・実行時の標準出力/標準エラーは実行されたタイミングで出力される

・正常時には標準出力を返す

・異常時には subprocess.CalledProcessError 例外を送出する


実行サンプル

import subprocess

print '!!! start'

cmd = 'echo aaa'
d = subprocess.check_output(cmd.split())
print d,

cmd = 'unexist_command'
try:
d = subprocess.check_output(
cmd.split(),
stderr=subprocess.STDOUT,
shell=True)
print d,
except subprocess.CalledProcessError as e:
print e.returncode
print e.cmd
print e.output,

print '!!! end'



出力

!!! start

aaa
127
['unexist_command']
/bin/sh: unexist_command: command not found
!!! end


subprocess.check_output 使用時に標準エラーを取得する

以下のように、stderr=subprocess.STDOUT を指定する。


使用例

    d = subprocess.check_output(

cmd.split(),
stderr=subprocess.STDOUT,
shell=True)


subprocessの実行ディレクトリを変更する


cwd オプションの使用


実行ディレクトリの指定

subprocess.call(cmd, cwd=workdir)


実行例を以下に示す。


実行サンプル

import subprocess

d1 = subprocess.check_output(['pwd']) # 初期位置 /tmp
d2 = subprocess.check_output(['pwd'], cwd='/tmp/hoge') # 絶対パスでの確認
d3 = subprocess.check_output(['pwd']) # 他の移動の影響は受けない
d4 = subprocess.check_output(['pwd'], cwd='./hoge') # 相対パスでの確認

print 'case 1:'
print d1,
print d2,

print 'case 2:'
print d3,
print d4,



実行例

case 1:

/tmp
/tmp/hoge
case 2:
/tmp
/tmp/hoge

python subprocess changing directory - Stack Overflow


注意点

実行コマンドを外部から取り込む場合、特に shell=True を指定している場合は、コマンド注入攻撃をされる場合が想定されるため、セキュリティには十分注意すること


補足:コマンド注入攻撃 / Shell Injection

IPA ISEC セキュア・プログラミング講座:Webアプリケーション編 第6章 入力対策:コマンド注入攻撃対策

Code injection - Wikipedia


不明な動作

check_outputshell=Trueを指定した場合に、標準出力/標準エラーが取得できない場合がある。(空文字列が返る)


参考

Python の subprocess で出力を受け取るときは communicate() を使おう - Qiita

pythonでコマンド実行するには - それマグで!