Python 3.5 以降では、外部コマンドの実行には subprocess.run() を使うことが推奨されている。
従来使用されていた subprocess.call(), check_call(), check_output() は現在も動作するが、run() を使うことで多くの用途を一つの関数でカバーできる。
run() は外部コマンドを実行し、終了コード・標準出力・標準エラーをまとめて扱える。
result = subprocess.run(cmd, shell=True, capture_output=True, text=True)
主な引数:
capture_output=True: 標準出力・エラーを取得
text=True: 文字列として取得(デコード不要)
check=True: 終了コードが 0 でない場合に例外(CalledProcessError)を発生
従来の関数 → subprocess.run() での代替
subprocess.call() run(...).returncode を見る
subprocess.check_call() run(..., check=True)
subprocess.check_output() run(..., capture_output=True, text=True, check=True).stdout
従来の書き方:
fns_ = subprocess.check_output(
'find ' + bdir + ' -name "zos*.nc"', shell=True
).decode('ascii').split('\n')
if fns_[-1] == '':
fns_ = fns_[:-1]
これを run() に書き換えると次のようになる:
result = subprocess.run(
f'find {bdir} -name "zos*.nc"',
shell=True,
capture_output=True,
text=True,
check=True
)
fns = result.stdout.split('\n')
if fns[-1] == '':
fns = fns[:-1] # 最後に空行が入るため削除
text=True を使うことで、Python 3.6+ では decode() の必要がない。
より細かい制御が必要な場合(逐次出力の取得、パイプ処理など)には Popen が使える。
communicate() を呼ぶと、標準出力・標準エラーを取得できる。
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = p.communicate()
ただし、多くの場合は subprocess.run() で十分であり、Popen を直接使う場面は減っている。
os.system()(戻り値は終了コードのみ)
commands.getoutput()(Python 2 系の関数)
これらは現在は使われない。