コマンド実行をする
コレを使います。
import subprocess import shlex ret = subprocess.check_output(shlex.split("date -I")).decode("UTF-8").strip() print(ret)
詳しく書いていきます。
subprocess モジュールを使う
subprocess はコマンド実行がちょっと面倒臭い。
import subprocess input_f = "player.swf" output_f = "radiko.png" cmd = "/usr/local/bin/swfextract -b 14 %s -o %s" % (input_f, output_f ) subprocess.call( cmd.strip().split(" ") )
subpcorcess.call は配列でコマンドとコマンドの引数を与える。 面倒なので、コマンド文字列を作ってから、split(" ") で文字列を分割して配列にしたら楽かも。
シェル経由で実行する
シェル経由で実行すると楽ちんですよね。
bash の場合
バッククォート演算子を使って文字列を囲うだけで出来る。
`wget -O index.html http://www.yahoo.co.jp `
python をシェル経由で実行するには
call に shell=True のキーワード引数をつけるだけ。
import subprocess cmd = "ls -lt | head -n 5" subprocess.call( cmd, shell=True )
これで、シェル経由実行される
subprocess.call([cmd,arg1,arg2..], shell=True)は 旧来のos.system の実行と同じ
import os cmd = "ls -lt " os.system( cmd )
os.system はすでにサポートされなくなりつつあるので、subprocessを使う方がいいようです。
シェル経由とは
シェル経由で実行するとは、こういうこと。
sh -c "コマンド"
のように、sh -c をつけて実行していることに相当する。
コマンドの文字列をそのまま渡せるので、Shell=Trueを使う人が多いとは思います。
コマンドの実行結果を取得したい
bash なら
ret=`ls -lt ` echo $ret
とするだけなのですが。
python のsubprocess モジュールで実行するには、check_outputを使う
import subprocess cmd = "ls -lt " ret = subprocess.check_output( cmd.split(" ") ) print ret
コマンドの実行終了をチャント待つには
check_callを使う。
import subprocess cmd = "ls -lt " ret = subprocess.check_call( cmd.split(" ") ) print ret == 0
実行結果が正常終了なら0がかえってくる。
call でパイプラインをチャント渡すには。
subprocessにシェル経由実行するように渡すと、パイプラインでもシッカリ処理してもらえる。
import subprcoess cmd = "ls -lt | head -n 5" subprocess.call( cmd , shell=True )
非シェル経由で呼び出すには。
subprocess のPIPEとstdoutを使うと実現できる。
cmd1 = "ls -lt " cmd2 = "head -n 5 " p1 = subprocess.Popen(cmd1.strip().split(" "), stdout=subprocess.PIPE) p2 = subprocess.Popen(cmd2.strip().split(" "), stdin=p1.stdout) p1.stdout.close() output = p2.communicate()[0]
非シェル経由の場合コマンドの実行をパイプ経由で送るには、ちょっと面倒臭い手続きが必要になる。
最後の2行はおまじない
p1.stdout.close()
output = p2.communicate()[0]
これを書くことで、Python の実行を CTRL+C をで止めた時に、サブプロセスがちゃんと終了してくれる。書かないとゴーストで残る。時間のかかる処理をしていると怖い。
ただ、シェル経由しない実行は、コマンド・インジェクション対策などで使えるので重要なテクニックになると思う。
getoutput より、check_output
getoutput の紹介記事が増えているが、シェル経由なので注意が必要
# getoutput より、check_output cmds = shlex.split('which ls;') ret= subprocess.check_output(cmds)
上記の例は、check_outputであればエラーだが、getoutputでは実行される。
getoutput は、プロセス起動せずに、シェルに文字列を渡すので、インジェクションを引き起こしやすい。なので、固定文字以外に使うべきではない。変数を入れてはいけない。変数をエスケープするくらいなら、はじめからgetoutputを避けるべき。
2016-06-28追記
spawn という名前はイメージしやすかったけどなくなりました。
2018-09-18
追記
2024-08-08 追記
getoutput の使い分けがかなり重要だと思うので追加。