HOWTO · Python
Python で Bash コマンドを実行する方法
このチュートリアルでは、Git コマンドに焦点を当てて、Python で bash コマンドを実行する方法を示します。subprocess や os.system など、コマンドを効果的に実行するための最良の方法を学びます。実用的な例と明確な説明でワークフローを改善しましょう。タスクを自動化し、プロセスを合理化したい開発者に最適です。
このページの内容
Python は、ディレクトリの作成や Git の使用といったタスクのために、コマンドラインプログラムやシェルコマンドを起動できます。終了するコマンドについては、subprocess.run() が通常最良の出発点です。出力とエラーをキャプチャでき、リターンコードを提供します。キャプチャした出力を必要としない単純なケースでは os.system() を使い、実行中のプロセスとやり取りする必要がある場合は subprocess.Popen() を選んでください。
subprocess.run() でコマンドを実行する
引数のシーケンスを渡して、実行ファイルを直接呼び出します。これにより、シェルにコマンドを解析させることを避けられます。この例では実行中の Python インタープリタを使うため、Git がインストールされていることにも、特定のシェルにも依存しません。
import subprocess
import sys
result = subprocess.run(
[sys.executable, "-c", "print('Hello from Python')"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
print("stdout:", result.stdout)
print("stderr:", result.stderr)
print("return code:", result.returncode)
stdout: b'Hello from Python\n'
stderr: b''
return code: 0
ここでは stdout と stderr はバイトであり、returncode は整数です。リターンコード 0 は慣例的に成功を示し、0 以外の値はプログラムが問題を報告したことを示します。自分で確認することも、check=True を渡して、0 以外のリターンコードに対して run() が CalledProcessError を発生させるようにすることもできます。たとえば Git を実行するには、['git', 'status'] のような引数リストを渡します。その出力はリポジトリに依存するため、固定の内容を持つと想定せず、データとして扱うべきです。
プログラムの呼び出しが自動的に Bash コマンドになるわけではありません。パイプ、リダイレクト、&& のようなシェル構文にはシェルが必要です。shell=True を設定すると、Python にプラットフォームのシェルを使うよう指示しますが、Bash であることを保証するものではありません。信頼できない入力をシェルコマンドに補間することは避けてください。コマンドインジェクションを可能にするおそれがあります。
os.system() でシェルコマンドを実行する
os.system() は、出力をキャプチャしたりエラーを詳しく処理したりする必要がない単純なコマンドに対する限定的な選択肢です。たとえば、os.system("mkdir reports") はプラットフォームのシェルにディレクトリ作成コマンドの実行を依頼します。コマンドは継承したコンソールストリームに書き込みます。この関数はコマンドの通常の出力ではなくステータス値を返します。そのステータスの解釈はプラットフォームによって異なる場合があります。キャプチャした出力、エラー、リターンコードを一貫して確認する必要がある場合は subprocess.run() を優先してください。
進行中のプロセスに subprocess.Popen() を使う
プログラムが終了する前に入力やその他のやり取りを必要とする場合は subprocess.Popen() を使います。プロセスを開始し、コードが扱えるプロセスオブジェクトを提供します。出力に上限があるプロセスについては、stdout=subprocess.PIPE と stderr=subprocess.PIPE を設定し、次に communicate() を呼んでそれらのストリームを読み取り、完了を待ちます。返されるストリーム値は、デコードを別途用意しない限りバイトです。
communicate() は、プロセスが終了し、そのキャプチャした出力がメモリに収まる場合に役立ちます。上限のない出力に対するストリーミング手法ではありません。communicate() が完了するとプロセスは終了しているため、そのプロセスに対して kill() や terminate() を呼ぶ必要はありません。単に終了する通常のコマンドについては、run() がより単純なインターフェースを提供します。
適切な方法を選ぶ
ほとんどのコマンドには subprocess.run() を使ってください。引数リストを渡し、必要に応じてストリームをキャプチャし、returncode を確認します。短いシェルコマンドで十分で、その出力や詳細なステータスが重要でない場合にのみ os.system() を使ってください。プログラムが実行中のプロセスを管理したり、それとデータを交換したりしなければならない場合は Popen() を使ってください。コマンドがシェル構文を必要とする場合にのみシェルを選び、信頼できない値を補間されるシェル文字列に含めないでください。