Python初心者の友人がバッチファイルの真似事をしようとして、Pythonで外部プログラムの呼び出しかたが分からず悩んでいました。自分自身も初心者のころつまった経験があるので、メモしておきます。
外部プログラムを扱う方法はたくさんある
- os (system, spawn*, popen*)
- popen2 (popen*)
- subprocess (Popen, call, check_call)
しかし、osやpopen2の関数はC言語のsystem関数などに慣れた人向けと思われ、
普通は高機能なsubprocessモジュールを使う方がよいです。
外部プログラムを起動する例
from subprocess import check_call check_call(["ls", "-s"]) # call(["ls", "-s"])
パイプなどに関係なく、単に他のプログラムを動かしたいだけなら、check_callやcallを使います。
check_callは起動した外部プログラムの終了コードが0でない場合に例外が発生します。callは終了コードをそのまま返します。終了コードが0でないというのは、エラーが発生したと言うことでしょうから、check_callを使う方がよいでしょう。
パイプで他のプログラムから読み込む例
stdout=PIPEを使うと、起動した外部プログラムの標準出力から文字列を受け取ることができます。
# lsを実行して、その結果を文字ずつ読み込みます。 from subprocess import Popen, PIPE p = Popen(["ls", "-s"], stdout=PIPE) while 1: # 一文字ずつ読み込んでは表示 c = p.stdout.read(1) if not c: break print c, p.wait() #子プロセスが終わるまでまつ。
lsのようなすぐ終わるコマンドでは意味がないですが、実行に時間がかかるコマンドの場合は、少しずつ読み込む必要があるかもしれません。
パイプで他のプログラムに書き込む例
stdin=PIPEを使うと、起動した外部プログラムの標準入力に文字列を渡すことができます。
# gnuplotにsinのグラフを表示させます。 from subprocess import Popen, PIPE import math print "plot sin(x - delta*pi)" p = Popen("gnuplot", stdin=PIPE) while 1: delta = float(raw_input("delta?").strip()) p.stdin.write("plot sin(x - %f*pi)\n" % (delta,))
特にgnuplotのように対話的に操作する場合は、Popenを活用できるかもしれません。
もちろん、stdin=PIPEとstdout=PIPEは同時に使うこともできます。
また、stderr=STDOUTを指定するとエラー出力を標準出力と一緒に得ることができます。
詳しくは、Pythonドキュメントのsubprocessの項を参照してください。