Pythonのsubprocessモジュールとrun
関数の詳細解説
Pythonには外部コマンドを実行するためのいくつかの方法がありますが、その中でも標準的に利用されるのがsubprocess
モジュールです。このモジュールを使うことで、Pythonスクリプトからシェルコマンドや他のプログラムを呼び出すことができます。具体的なユースケースとしては、シェルスクリプトを実行したり、外部プログラムに引数を渡して結果を受け取るなどの処理が挙げられます。
今回の記事では、subprocess
モジュールのrun
関数に焦点を当てて、その基本的な使い方やオプションについて詳しく解説します。具体例を交えながら、実際のコードとその出力結果を確認しつつ進めていきます。
subprocess.run
とは
subprocess.run
は、Python 3.5で導入されたsubprocess
モジュール内の関数で、コマンドを実行し、その結果を取得するために使われます。それまで使われていたsubprocess.call
やsubprocess.check_output
よりも柔軟で扱いやすくなっており、現代的なPythonのコードでは一般的にこのrun
関数を使います。
subprocess.run
の基本的なシグネチャは以下の通りです。
subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, cwd=None, timeout=None, check=False, encoding=None, errors=None, text=None, env=None, universal_newlines=None)
これだけ見るとかなり多くの引数を取ることが分かりますが、まずは基本的な使い方を抑えることが大切です。次に、それぞれの引数について説明していきます。
基本的な使い方
subprocess.run
を使う際、最もシンプルな形は引数に実行したいコマンドをリスト形式で渡すことです。例えば、シェルコマンドでls -l
(ディレクトリの内容をリスト表示)を実行する場合、以下のように書きます。
import subprocess result = subprocess.run(["ls", "-l"])
この場合、subprocess.run
はCompletedProcess
オブジェクトを返します。このオブジェクトには、実行したコマンドの結果や終了ステータスなどが含まれています。CompletedProcess
の主な属性は次の通りです。
args
: 実行されたコマンドreturncode
: コマンドの終了コード(0は正常終了、それ以外は異常終了)stdout
: コマンドの標準出力stderr
: コマンドの標準エラー出力
それでは、このコードを実行した際の結果を見てみましょう。
実行結果
total 8 -rw-r--r-- 1 user staff 2048 Sep 28 14:25 example.txt -rw-r--r-- 1 user staff 1024 Sep 28 14:26 another_file.txt
このコードでは、シェルコマンドls -l
が実行され、指定されたディレクトリ内のファイル一覧が表示されます。
コマンドの標準出力を取得する
次に、実行したコマンドの結果(標準出力)をPython内で扱う方法を紹介します。これには、stdout=subprocess.PIPE
を使います。これにより、標準出力をパイプとして取得し、結果をCompletedProcess
オブジェクトのstdout
属性から取得できるようになります。
以下の例では、ls -l
の出力をPythonの変数として取得します。
import subprocess result = subprocess.run(["ls", "-l"], stdout=subprocess.PIPE, text=True) print(result.stdout)
実行結果
total 8 -rw-r--r-- 1 user staff 2048 Sep 28 14:25 example.txt -rw-r--r-- 1 user staff 1024 Sep 28 14:26 another_file.txt
このように、result.stdout
にコマンドの結果が文字列として格納されます。ここでtext=True
を指定している点に注意してください。これにより、バイトデータではなく文字列として結果が返されます。
エラー出力を取得する
コマンドが標準エラー出力にエラーメッセージを出力した場合、それも同様に取得することができます。これにはstderr=subprocess.PIPE
を使います。
次の例では、存在しないコマンドを実行してエラーメッセージを取得します。
import subprocess result = subprocess.run(["ls", "non_existing_file"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) print("stdout:", result.stdout) print("stderr:", result.stderr)
実行結果
stdout: stderr: ls: non_existing_file: No such file or directory
このように、標準出力と標準エラー出力をそれぞれ個別に取得することができます。
コマンドの終了コードを確認する
実行したコマンドが正常に終了したかどうかは、CompletedProcess
オブジェクトのreturncode
属性で確認できます。終了コードが0
であれば正常終了、それ以外の値であれば異常終了を意味します。
以下のコードでは、コマンドの終了コードをチェックし、異常終了した場合にエラーメッセージを出力する例を示します。
import subprocess result = subprocess.run(["ls", "non_existing_file"], stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True) if result.returncode != 0: print(f"Error: {result.stderr}")
実行結果
Error: ls: non_existing_file: No such file or directory
この例では、ls
コマンドが失敗しているため、エラーメッセージが表示されます。
check=True
によるエラーハンドリング
コマンドが異常終了した場合に自動的に例外を発生させたい場合、run
関数にcheck=True
を指定します。このオプションを使うと、終了コードが0
でない場合にsubprocess.CalledProcessError
が発生します。
以下の例では、存在しないファイルを指定してエラーを強制的に発生させ、そのエラーハンドリングを行います。
import subprocess try: subprocess.run(["ls", "non_existing_file"], check=True) except subprocess.CalledProcessError as e: print(f"Command failed with return code {e.returncode}")
実行結果
Command failed with return code 2
このように、check=True
を指定することで、異常終了時に明示的にエラーとして処理することが可能になります。
シェルコマンドの実行 (shell=True
)
通常、subprocess.run
でコマンドを実行する場合、コマンドはリスト形式で渡します。しかし、シェル固有の機能(例えば、パイプやリダイレクトなど)を使いたい場合は、shell=True
を指定する必要があります。
以下の例では、シェルの機能を使って、echo
コマンドの出力をgrep
でフィルタリングしています。
import subprocess result = subprocess.run("echo 'hello world' | grep hello", shell=True, stdout=subprocess.PIPE, text=True) print(result.stdout)
実行結果
hello world
ここでshell=True
を使わなければ、パイプを含むコマンドは正しく実行されません。シェルコマンドを直接実行する必要がある場合にのみ、このオプションを使います。
タイムアウトの設定
subprocess.run
にはtimeout
オプションもあります。これを使うことで、コマンドが指定した時間内に終了しなかった場合にTimeoutExpired
例外を発生させることができます。
次の例では、sleep
コマンドで2秒待機しようとしますが、タイムアウトを1秒に設定しているため、例外が発生します。
import subprocess try: subprocess.run(["sleep", "2"], timeout=1) except subprocess.TimeoutExpired: print("The command timed out")
実行結果
The command timed out
環境変数の設定 (env
)
subprocess.run
では、実行するコマンドに対してカスタムの環境変数を渡すことも可能です。これには、env
引数を使います。例えば、以下のコードでは、新しい環境変数MY_VAR
を設定して、printenv
コマンドでその値を確認しています。
import subprocess import os env = os.environ.copy() env["MY_VAR"] = "Hello" result = subprocess.run(["printenv", "MY_VAR"], stdout=subprocess.PIPE, env=env, text=True) print(result.stdout)
実行結果
Hello
まとめ
subprocess.run
は、Pythonで外部コマンドを実行するための非常に強力で柔軟な関数です。今回の記事では、基本的な使い方から標準出力・エラーの取得、タイムアウトや環境変数の設定など、実践的な例を交えて詳しく解説しました。