Pythonとsubprocessで成功する!10の実例入り詳解ガイド

Pythonとsubprocessで成功する方法を学ぶ初心者のためのイラストPython
この記事は約12分で読めます。

 

【サイト内のコードはご自由に個人利用・商用利用いただけます】

この記事では、プログラムの基礎知識を前提に話を進めています。

説明のためのコードや、サンプルコードもありますので、もちろん初心者でも理解できるように表現してあります。

基本的な知識があればカスタムコードを使って機能追加、目的を達成できるように作ってあります。

※この記事は、一般的にプロフェッショナルの指標とされる『実務経験10,000時間以上』を凌駕する現役のプログラマチームによって監修されています。

サイト内のコードを共有する場合は、参照元として引用して下さいますと幸いです

※Japanシーモアは、常に解説内容のわかりやすさや記事の品質に注力しております。不具合、分かりにくい説明や不適切な表現、動かないコードなど気になることがございましたら、記事の品質向上の為にお問い合わせフォームにてご共有いただけますと幸いです。
(送信された情報は、プライバシーポリシーのもと、厳正に取扱い、処分させていただきます。)

はじめに

Pythonとsubprocessの組み合わせは、プログラミングの世界で幅広く使われています。

シェルコマンドをPythonスクリプトから直接操作できるsubprocessモジュールは、コーディングの自由度を飛躍的に向上させ、作業の効率化を図ることが可能です。

しかし、その使い方や活用方法について疑問を抱く初心者の方も多いのではないでしょうか。

今回はPythonとsubprocessの基本から活用法、さらには詳細な注意点やカスタマイズ方法まで、一から徹底的に解説していきます。

●Pythonとsubprocessとは?

まずは、Pythonとsubprocessの基本について解説します。

○Pythonの基本

Pythonは、コードがシンプルで可読性が高く、さまざまなプラットフォームで動作することから幅広く用いられているプログラミング言語です。

科学技術計算やデータ分析、Web開発など、様々な用途に使用することができます。

○subprocessの基本

一方、subprocessはPythonの標準ライブラリの一つで、新しいプロセスを生成、そのプロセスの入出力を取得し、終了ステータスを取り扱うことができます。

これにより、シェルコマンドを直接Pythonスクリプトから操作することが可能となります。

●subprocessの使い方

では、具体的なsubprocessの使い方を見ていきましょう。

サンプルコードを用いて、基本的な活用方法から詳細な使い方までを学んでいきます。

○サンプルコード1:コマンドを実行する

Pythonのsubprocessモジュールを使って、シェルコマンドを実行する基本的なコードを紹介します。

この例では、subprocess.run()関数を使って、’ls’コマンドを実行しています。

import subprocess

subprocess.run(['ls'])

上記のコードは、現在のディレクトリの内容を一覧表示する’ls’コマンドを実行するものです。

subprocess.run()関数には、実行したいコマンドを引数として渡します。

このとき、コマンドは文字列のリストとして渡す必要があります。

○サンプルコード2:出力結果を取得する

次に、コマンドの出力結果を取得する方法を見ていきましょう。

この例では、subprocess.run()関数に’capture_output=True’という引数を追加して、出力結果を取得しています。

import subprocess

result = subprocess.run(['ls'], capture_output=True)
print(result.stdout)

このコードは、’ls’コマンドを実行し、その結果を取得して表示します。

capture_output=Trueを設定することで、標準出力と標準エラー出力を取得することができます。

出力はバイト列として取得されるので、必要に応じて文字列に変換することが可能です。

○サンプルコード3:エラーハンドリング

subprocessを使用する際には、エラーハンドリングも重要です。

次の例では、存在しないコマンドを実行しようとした際のエラーハンドリングを示します。

import subprocess

try:
    subprocess.run(['non_existing_command'], check=True)
except subprocess.CalledProcessError as e:
    print('Error occurred: ', e)

このコードでは、存在しない’non_existing_command’を実行しようとしています。

check=Trueを設定すると、コマンドが0以外のステータスコードで終了した場合にsubprocess.CalledProcessErrorが投げられます。

これをtry-exceptブロックでキャッチし、エラーが発生したことを報告しています。

○サンプルコード4:コマンドに引数を渡す

コマンドに引数を渡すことも可能です。

この例では、’ls’コマンドに’-l’という引数を渡しています。

import subprocess

subprocess.run(['ls', '-l'])

このコードは、詳細なファイル情報を一覧表示する’ls -l’コマンドを実行します。

コマンドとその引数は同じリストに含めて、subprocess.run()関数に渡します。

●subprocessの詳細な対処法

subprocessモジュールの活用では、一部の微妙な挙動やハンドリングが求められる場面があります。

これらは、プロセスの終了を待つ方法やタイムアウトを設定する方法など、具体的には次の項目で説明します。

○サンプルコード5:プロセスの終了を待つ

このコードでは、subprocessモジュールを使ってプロセスの終了を待つ方法を紹介します。

この例では、subprocess.run()関数を使ってコマンドを実行し、その終了を待ちます。

import subprocess

# 'ls -l' コマンドを実行
proc = subprocess.run(['ls', '-l'])

# プロセスの終了を待つ
proc.wait()

このコードは、’ls -l’というコマンドを実行しています。

このコマンドは、Unix系のOSでディレクトリの詳細なリストを表示するためのコマンドです。

そして、wait()メソッドを使ってプロセスの終了を待っています。

プロセスが終了すると、wait()メソッドは制御を返し、プログラムは次の行に進みます。

○サンプルコード6:タイムアウトを設定する

このコードでは、subprocessモジュールでタイムアウトを設定する方法を紹介します。

この例では、subprocess.run()関数にtimeout引数を指定して、コマンドの実行時間を制限します。

import subprocess

try:
    # 'sleep 5' コマンドを実行、ただし最大実行時間は3秒
    proc = subprocess.run(['sleep', '5'], timeout=3)
except subprocess.TimeoutExpired:
    print('コマンドの実行時間がタイムアウトしました。')

このコードでは、’sleep 5’というコマンドを実行しています。

このコマンドは、プログラムを5秒間停止するUnix系のOSのコマンドです。

そして、timeout引数に3を指定することで、コマンドの最大実行時間を3秒に制限しています。

もしコマンドの実行時間が3秒を超えると、subprocess.TimeoutExpired例外が発生します。

この例外は、try-exceptブロックで捕捉して適切に処理しています。

●subprocessの詳細な注意点

Pythonのsubprocessモジュールを使う際には、セキュリティやエンコーディングに関するいくつかの注意点が存在します。

これらの注意点を理解し、適切に対処することで、より安全で効果的なコードを書くことができます。

○サンプルコード7:セキュリティ上の注意点

このコードでは、セキュリティ上の注意点を示すための例として、シェルの脆弱性を利用した攻撃の可能性を表しています。

この例では、ユーザーからの入力をそのままコマンドとして実行する場面での問題を指摘しています。

import subprocess

# ユーザーからの入力を受け取る
user_input = 'foo; rm -rf /'

# ユーザーの入力をそのままコマンドとして実行する
# これは非常に危険!
proc = subprocess.run(user_input, shell=True)

このコードでは、ユーザーからの入力をそのままシェルのコマンドとして実行しています。

しかし、これは非常に危険な行為です。

なぜなら、悪意のあるユーザーが’;’を使ってコマンドを追加することで、任意のコマンドを実行できてしまうからです。

例えば、’foo; rm -rf /’という入力を受け取ると、’rm -rf /’という危険なコマンドが実行されてしまいます。

このようなシェルの脆弱性を利用した攻撃を防ぐためには、ユーザーからの入力をそのままコマンドとして実行しないことが重要です。

代わりに、subprocess.run()関数の第一引数にコマンドをリスト形式で渡すと、シェルの脆弱性を利用した攻撃を防げます。

○サンプルコード8:エンコーディングに関する注意点

このコードでは、エンコーディングに関する注意点を説明します。

この例では、subprocess.run()関数の実行結果をテキストとして取得するために、encoding引数を使います。

import subprocess

# 'echo Hello, World!' コマンドを実行し、結果をテキストとして取得
proc = subprocess.run(['echo', 'Hello, World!'], capture_output=True, text=True)

# コマンドの実行結果を出力
print(proc.stdout)

このコードでは、’echo Hello, World!’というコマンドを実行しています。

そして、capture_output引数をTrueに設定することで、コマンドの実行結果を取得しています。

さらに、text引数をTrueに設定することで、実行結果をテキストとして取得しています。

しかし、このコードには一つの注意点があります。

それは、encoding引数を指定しないと、実行結果のテキストはOSのデフォルトエンコーディングを使ってデコードされるという点です。

このデフォルトエンコーディングはOSによって異なるため、予期せぬ文字化けを引き起こす可能性があります。

そこで、encoding引数を使って明示的にエンコーディングを指定することが推奨されます。

●subprocessの詳細なカスタマイズ

subprocessモジュールは、外部プロセスを生成・操作するための非常に強力なツールです。

しかし、その力を最大限に活用するためには、subprocessが提供する機能を細かくカスタマイズすることが必要です。

それでは、subprocessを用いて環境変数をカスタマイズしたり、プロセスに入力を送信したりする方法について詳しく解説していきます。

○サンプルコード9:環境変数をカスタマイズする

このコードでは、subprocessモジュールを使って新しいプロセスを生成し、そのプロセスの環境変数をカスタマイズする方法を表しています。

この例では、新しいプロセスの’PATH’環境変数を変更しています。

import subprocess
import os

# 現在の環境変数をコピー
new_env = os.environ.copy()

# PATH環境変数に追記
new_env['PATH'] = '/usr/local/myapp:' + new_env['PATH']

# 新しい環境変数でコマンドを実行
proc = subprocess.run(['mycommand'], env=new_env)

このコードでは、まずos.environ.copy()を使って現在の環境変数をコピーします。

次に、このコピーした環境変数の’PATH’をカスタマイズします。

そして、subprocess.run()関数のenv引数にこの新しい環境変数を渡して、新しいプロセスを生成します。

この新しいプロセスは、カスタマイズした’PATH’環境変数を使うことになります。

このように、subprocessモジュールを使って新しいプロセスの環境変数をカスタマイズすることができます。

これにより、プロセスの挙動をより詳細にコントロールすることが可能になります。

○サンプルコード10:入力を送信する

このコードでは、subprocessモジュールを使って新しいプロセスに入力を送信する方法を表しています。

この例では、’grep’コマンドに文字列を送信しています。

import subprocess

# 'grep'コマンドを実行
proc = subprocess.Popen(['grep', 'hello'], stdin=subprocess.PIPE)

# 'grep'コマンドに入力を送信
proc.communicate(input=b'hello world\n')

このコードでは、まずsubprocess.Popen()関数を使って新しいプロセスを生成します。

そして、stdin引数にsubprocess.PIPEを指定することで、この新しいプロセスに対して入力を送信する準備をします。

最後に、communicate()メソッドを使って’grep’コマンドに’hello world\n’という入力を送信します。

このように、subprocessモジュールを使って新しいプロセスに対して入力を送信することができます。

これにより、コマンドラインで対話的に操作するようなプログラムも、Pythonから制御することが可能になります。

まとめ

Pythonのsubprocessモジュールは、外部コマンドの実行を可能にする強力な機能を備えています。

今回はその詳細な使い方を解説し、実例を交えながら具体的なカスタマイズの手順をお伝えしました。

初めてsubprocessモジュールを利用する方でも、一から理解できるように詳しく説明しました。

本記事では、subprocess.runやsubprocess.Popenをはじめとする基本的なメソッドの使用法から、新しいプロセスの生成、環境変数のカスタマイズ、プロセスへの入力の送信方法など、subprocessモジュールの多岐にわたる機能を解説しました。

これらの情報を元に、より高度なシステム制御や自動化を実現することができるでしょう。

Pythonはその豊富なライブラリと簡潔な文法により、さまざまなシーンで活用されています。

その一つが、外部コマンドの実行とそれらの結果の取得、管理です。

subprocessモジュールはそのための強力なツールであり、本記事で紹介したテクニックを活用すれば、更にその可能性を広げることができます。

Pythonとsubprocessモジュールを活用して、より良いソフトウェアを作り上げることを応援しています。今回学んだことをぜひ実践に生かしてみてください。

今後ともPythonの世界を楽しみながら、スキルアップしていきましょう。