.net column
.NET開発者のためのブログメディア

アプリ開発ツール

Pythonのsubprocessモジュールの使い方|子プロセスの起動方法からわかりやすく解説

2021年03月25日
SE
Pythonのsubprocessモジュールの使い方について教えていただけますか。
PM
Pythonのsubprocessモジュールの使い方や子プロセスの起動方法、バックグラウンドでの実行方法、子プロセスだけでなく孫プロセスまでkillする方法などについて、Windows10を使用して解説いたしましょう。

Pythonのsubprocessとは?


Pythonのsubprocessとは一般的には子プロセス(child process)と呼ばれるプロセスを起動したりするためのモジュールです。

ここでは新しく用意された関数等を用いて解説しますのでPython3.5以降のできるだけ新しいバージョンで実行してください。以降Windows10と、その上で走るPython3.9.1を使って解説します。

コマンドを入力して子プロセスを起動する

Pythonではsubprocessモジュールを利用することで比較的簡単に子プロセスを起動することができます。まずはコマンドを入力して起動してみます。

では実際にやってみましょう。

Pythonのsubprocessを使うための準備

Pythonのsubprocessモジュールを使うためにはsubprocessモジュールをインポートする必要があります。

Pythonのコマンド待ち状態のときに下記のように入力すればsubprocessモジュールをインポートできます。ちなみにこれは使う前に1度だけ実行すればOKです。

簡単な子プロセスの起動方法

Pythonのsubprocessモジュールのrun関数を使って子プロセスを起動します。

とりあえず「メモ帳」を起動してみることにします。下記のコマンドを実行してみてください。

Windowsのシェルについて

Windows標準のシェルはコマンドプロンプト(cmd.exe)です。

コマンドプロンプトを開いてsetコマンドを実行し(「set」と入力してEnterキーを押せば表示されます)、環境変数ComSpecの設定を確認してみてください。デフォルト設定のシェルを確認できます。

シェルのdirコマンドを実行してみる

Windows標準のシェルであるコマンドプロンプト(cmd.exe)のdirコマンドを実行してみます。下記のコマンドを実行してdirコマンドが実行されるかを確認してください。

引数shellにTrueを指定していますが、これは「シェル(コマンドプロンプト)を起動して実行します」という意味です。dirコマンドは内部コマンドですのでコマンドプロンプトを起動しないと実行できません。ご注意ください。

また、subprocess.runでコマンドシェル用のコマンドを実行する場合には、内部コマンドか外部コマンドかに関わらず「shell=True」を指定しておいた方が不具合は出ません。

なお、subprocess.runには引数timeoutがあり、指定するとタイムアウトを設定できます。タイムアウトが発生するとTimeoutExpired例外が発生します。処理の仕方はPopen.communicateと同様ですので、次の項の「バックグラウンドによる実行」をご覧ください。

バックグラウンドによる実行

Pythonのプログラム中から「子プロセスを起動したい」ときというのは大抵「バックグラウンドで実行したい」ときではないでしょうか。subprocessでバックグラウンド実行したいときはsubprocess.Popenを用います。

Popenを使って外部コマンドを起動するときはシェルを起動しない方が良いでしょう。理由はタイムアウトで子プロセスをkillしたいときなどのときに、シェルの子プロセス(つまり孫プロセス)になってしまうため、killメソッドではkillできなくなるからです。

Popenを使ったサンプルプログラム

下記のプログラムはWindowsのtimeoutコマンドを使った動作確認用プログラムです。

Popenに与えているコマンドはリスト型になっています。シェルを起動しないのでコマンドライン解析ができないためリスト型で与える必要があります。

Popenを使った行でバックグラウンド実行したいコマンドを実行しています。stdoutにsubprocess.PIPEを指定するとコマンド実行後に標準出力に出力された結果が得られます。「5」は5秒待つという意味のオプションです。適当に変えて実行してみてください。

communicateでtimeout指定すると指定時間経過しても子プロセスが終了しなかったときに例外のTimeoutExpiredが発生します。communicateを実行するとプロセスが終了するかタイムアウトするまで制御が戻ってこなくなりますので注意してください。

なお、print文で出力されるtimeoutコマンドの出力メッセージはエスケープシーケンスが使用されているため、メッセージの一部しか表示されません。

こちらが実行結果になります。

subprocessで起動した孫プロセスをkillする

普通にkillメソッドでkillすると子プロセスしかkillすることはできません。しかし、孫プロセスまでkillする方法があります。それはtaskkillという外部コマンドを使う方法です。

taskkillコマンドにPID(プロセスID)と適切なオプションスイッチを渡すことで孫プロセスまでkillすることができます。

下記のプログラムを実行すると15秒後に起動したシェルとtimeoutコマンドの2つのプロセスをkillします。なお、この方法はバッチファイルを起動したときなども有効です。

こちらが実行結果になります。

Pythonのsubprocessの使い方

subprocessのおすすめの使い方を紹介します。

まず子プロセスの実行完了待ちができる場合はsubprocess.runが手軽で良いと思います。バックグラウンドで実行したいときはsubprocess.Popenで起動して、適当なタイミングでPopen.pollメソッドで実行完了しているかを確認すると良いでしょう。

バックグラウンドで実行したとき、引数stdoutにsubprocess.PIPEを指定すれば実行完了時に標準出力に出力されたメッセージを取得することができます。

バックグラウンドで実行したとき、起動した子プロセスを強制終了するにはPopen.killメソッドを使用します。また、孫プロセスまで強制終了するにはtaskkillコマンドを使用します。

SE
Pythonのsubprocessモジュールの使い方や子プロセスの起動方法、バックグラウンドでの実行方法がよく分かりました。
PM
ご紹介した方法を参考にして、ご自身でソースコードを書いてみてください。

最後に

以上、subprocessの使い方について一通り解説しました。

子プロセスを制御できるようになれば、他の言語で作ったプログラム(.exeファイル)を起動して処理しながらPythonの方でも処理をすることができるようになりますので効率よく作業ができるようになるでしょう。


.NET分野でのキャリアアップをお考えの方は、現在募集中の求人情報をご覧ください。

また、直接のエントリーも受け付けております。

エントリー(応募フォーム)

Search

Popular

reccomended

Categories

Tags