概要
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 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_output
でshell=True
を指定した場合に、標準出力/標準エラーが取得できない場合がある。(空文字列が返る)
参考
Python の subprocess で出力を受け取るときは communicate() を使おう - Qiita
pythonでコマンド実行するには - それマグで!