subprocess¶
はじめに¶
subprocessの目的は、以下のモジュールを置き換えることです。
- os.system
- os.spawn*
- os.popen*
- popen2.*
- commands.*
commands¶
subprocess.getoutputで置き換えることができます。 ただし、これは互換性を保つためのものなので、 check_outputを使用してください。
出力を関数の戻り値にする場合¶
関数check_outputを使用します。
out = subprocess.check_output(["ls", "-l"])
これは、Popenを簡略した書き方です。
実際は
popen = subprocess.Popen(["ls", "-l"], stdout=subprocess.PIPE)
out = popen.communicate()[0]
と同じ結果になります。
Warning
出力が何も無いとエラーが返ってきます。
subprocess.check_output("ls |grep abc")
#CalledProcessError
#non-zero exit status 1
universal_newlines=Trueにした場合は、 出力をテキストとして扱います。 そのため、出力結果がdecodeされます。
os.systemの代わりの関数を自作するのであれば
def system(cmd):
return subprocess.check_output(cmd, shell=True, universal_newlines=True)
となります。
エラーが返ってきた場合の処理¶
subprocess.check_call関数を使用します。
try:
subprocess.check_call(["ls", "a"]) # -aのハイフンが抜けてます
except CalledProcessError:
sys.exit(1)
pipe¶
複数のコマンドを連ねたパイプを実装します。
#ls -a | grep .py
ls = subprocess.Popen(["ls", "-a"], stdout=subprocess.PIPE)
grep = subprocess.Popen(["grep", ".py"], stdin=ls.stdout, stdout=subprocess.PIPE)
stdoutにPIPEを指定しないと、結果がディスプレイに出力されてしまいます。
正直、僅かなコマンドを書くのに、これだけの記述は面倒し分かりにくいです。その場合
from subprocess import check_out
out = check_out("ls -a | grep .py", shell=True).decode("utf-8")
とすれば、比較的簡単に記述ができます。
Popenオブジェクト¶
Popenで返すオブジェクトは以下の属性を持ちます。
- communicate
- pid
- poll
- send_signal
- terminate
- kill
- wait
- returncode
また、ファイルオブジェクトも持ち合わせています。
- stdin
- stdout
- stderr
communicate¶
子プロセスと対話する¶
p = Popen(["cat"], stdin=PIPE, stdout=PIPE)
p.stdin.write("hoge\n")
os.read(p.stdout.fileno(), 1024)
#p.readline()
writeとreadを繰り返すことで、対話することが可能です。
p.communicateを使えとマニュアルには書いてあるが、それを使うと1回やり取りした時点でfdを閉じてしまうから2回目で「ValueError: I/O operation on closed file」