Python で外部プログラムを起動するには subprocess.run を使用します(Python 3.4 以前は subprocess.call を使用します)。
プログラム名と引数は、下記のようにタプルやリストで1つずつ分けて渡します。
import subprocess
result = subprocess.run(('ls', '-l'))
subprocess.run の shell パラメータを True に指定すると、渡したコマンドがシェル上で実行されるようになります。
例えば、Windows の dir コマンドなど、シェルに組み込まれているコマンドを実行したい場合や、シェル変数の展開、glob パターンの展開といったシェルの機能を使いたい場合は、shell パラメータを True に指定して実行する必要があります。
この場合は、プログラム名と引数を分けずに1つの文字列として指定します。
import subprocess
result = subprocess.run('dir *.txt', shell=True)
import subprocess
result = subprocess.run('echo $HOME', shell=True)
また、現在のシェルで PATH を通しているプログラムを実行したい場合なども、上記のように shell=True と指定するとうまく実行できます。
外部のプログラムを実行するには、以下のように os.system() を使う方法もありますが、os.system() は非推奨 (deprecated) となっていますので、今後は subprocess.run の方を使用しましょう。
import os
retcode = os.system('echo Hello')
外部プログラムの実行が成功したかどうかを調べるには、戻り値として返される CompletedProcess オブジェクトの returncode を確認します(正常に実行が完了していれば 0 が格納されている)。
import subprocess
result = subprocess.run('mycommand', shell=True)
if result.returncode != 0:
# エラー時の処理
あるいは、subprocess.run 実行時に check パラメータを True に設定しておくと、外部プログラムの実行に失敗したとき(リターンコードが 0 以外のとき)に subprocess.CalledProcessError 例外をスローするようになるので、これを補足 (except) するという方法もあります。
import subprocess
import sys
try:
subprocess.run('mycommand', shell=True, check=True)
except subprocess.CalledProcessError:
print('外部プログラムの実行に失敗しました', file=sys.stderr)
実際にエラー処理をしっかりと記述しなければいけないようなケースでは、外部プログラムが出力するエラーメッセージを Python プログラム内でハンドルしたいかもしれません。 そのような場合は、下記の「標準出力/エラー出力を取得する」で説明しているように、stdout や stderr への出力を Python プログラム側でハンドルするように記述してください。
subprocess.run の実行時に、stdout パラメータや stderr パラメータを subprocess.PIPE に設定しておくと、外部プログラムの出力を Python コード内でハンドルすることができるようになります。
出力がテキストの場合は、universal_newlines オプションも True に設定しておきます(デフォルトではバイナリデータとして取得されるため)。
import subprocess
import sys
try:
result = subprocess.run('dir *.txt', shell=True, check=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
for line in result.stdout.splitlines():
print('>>> ' + line)
except subprocess.CalledProcessError:
print('外部プログラムの実行に失敗しました', file=sys.stderr)
以下のようなユーティリティ関数 (command) を作っておくと、外部コマンドの出力を一行ずつ取得するコードを簡単に記述できて便利です。
import subprocess
import sys
def command(cmd):
try:
result = subprocess.run(cmd, shell=True, check=True,
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
universal_newlines=True)
for line in result.stdout.splitlines():
yield line
except subprocess.CalledProcessError:
print('外部プログラムの実行に失敗しました [' + cmd + ']', file=sys.stderr)
sys.exit(1)
# 使用例
for line in command('p4 info'):
print('===', line)
subprocess.Popen() の stdin パラメータに subprocess.PIPE を指定すると、以下のように外部プロセスの標準入力へ書き込むことができるようになります。
import subprocess
from subprocess import PIPE
with subprocess.Popen('sort', shell=True, stdin=PIPE, stdout=PIPE, stderr=PIPE,
universal_newlines=True) as pipe:
# sort コマンドへテキスト入力して、結果を受け取る
out, err = pipe.communicate('One\nTwo\nThree\nFour')
for line in out.splitlines():
print('===', line)
=== Four
=== One
=== Three
=== Two
下記のサンプルでは、dir コマンドの標準出力を、sort コマンドの標準入力へ接続しています。
import subprocess
from subprocess import PIPE
dir_result = subprocess.run('dir', shell=True, check=True,
stdout=PIPE, universal_newlines=True)
sort_result = subprocess.run('sort', shell=True, check=True,
input=dir_result.stdout, stdout=PIPE, universal_newlines=True)
for line in sort_result.stdout.splitlines():
print('===', line)
open() 関数で開いたファイルオブジェクトを、subprocess.run() の stdin パラメータにそのまま渡すことができます。
import subprocess
with open('input.txt', encoding='utf-8') as file:
proc = subprocess.run('sort', shell=True, check=True,
stdin=file, stdout=subprocess.PIPE, universal_newlines=True)
for line in proc.stdout.splitlines():
print('===', line)
ただ、これをやるのであれば、sort input.txt を実行してしまった方が早いですね。。