今回は、pythonプログラムからシェルコマンドを実行する方法を紹介します。subprocessというモジュールを使用します。今まで、os.systemモジュールを使用していましたが、ドキュメントを見ると非推奨となっていますので、subprocessモジュールに置き換えていこうと思っています。
subprocess.callを使用して、シェルコマンドを実行
シェルコマンドの戻り値が必要ない場合は、このcallというコマンドが手っ取り早く、シェルコマンドを実行できます。callの引数にシェルコマンドを記載するだけです。shlexモジュールでコマンドをトークン化してくれます。
import subprocess, shlex args = shlex.split("mkdir ./test") ret = subprocess.call(args) print(ret)
これで、カレントフォルダにtestフォルダが作成されます。戻り値、正常終了であれば、ret = 0、異常終了であれば、ret=1となります。
import subprocess, shlex args = shlex.split("sudo shutdown -h now") ret = subprocess.call(args)
上記プログラムで、Raspberry Piがシャットダウンします。
subprocess.runを使用して、シェルコマンドを実行
subprocess.runコマンドを使えば、標準出力(戻り値)、エラー出力が取得できます。ドキュメントでも推奨されています。
import subprocess, shlex args = shlex.split("ls -al") ret = subprocess.run(args, stdout = subprocess.PIPE, stderr = subprocess.PIPE) print(ret.returncode) # 終了コード print(ret.stdout.decode("utf-8")) # 標準出力 print(ret.stderr.decode("utf-8")) # エラー出力
戻り値はバイトコードで返ってきますので、utf-8に変換する必要があります。 runコマンドでほとんどの場合は、事足りると思います。
subprocess.Popenを使用して、シェルコマンドを実行
上記のsubprocess.runコマンドでは、実行から出力取得まで一連動作を一気に行います。その間、他の処理をすることができません。subprocess.Popenは実行と出力取得を分けて実行することができますので、その間に別の処理を実行することができます。
import subprocess, shlex args = shlex.split("時間がかかるコマンド") proc = subprocess.Popen(args, stdout = subprocess.PIPE, stderr = subprocess.PIPE) # (1) シェルコマンド実行 # subprocessとは別の処理 (2) try: outs,errs = proc.communicate(timeout=15) # (3) シェルコマンドの出力取得 except TimeoutExpired: # 15秒タイムアウトで例外処理 proc.kill() outs,errs = proc.communicate() print("stdout:" + outs.decode("utf-8")) # 標準出力 print("stderr:" + errs.decode("utf-8")) # エラー出力
subprocessの使い方は以上になります。