スレッド

[Python] subprocess.run関数の使い方 – サブプロセスの起動

subprocess.run関数は、Pythonで外部コマンドやプログラムを実行するために使用されます。

この関数は、サブプロセスを起動し、その終了を待機します。

基本的な使い方はsubprocess.run(["コマンド", "引数1", "引数2"], options)の形式で、リスト形式でコマンドと引数を指定します。

オプションとして、capture_output=Trueで標準出力とエラーを取得したり、text=Trueで出力を文字列として扱ったりできます。

戻り値はCompletedProcessオブジェクトで、returncodestdoutなどにアクセス可能です。

subprocess.run関数とは

subprocess.run関数は、Pythonのsubprocessモジュールに含まれる関数で、外部プログラムやコマンドを実行するために使用されます。

この関数を利用することで、Pythonスクリプトからシェルコマンドを呼び出したり、他のプログラムを実行したりすることができます。

主な特徴

  • 簡単なインターフェース: subprocess.runは、外部コマンドを実行するためのシンプルな方法を提供します。
  • 結果の取得: 実行したコマンドの標準出力や標準エラー出力を簡単に取得できます。
  • エラーハンドリング: コマンドの実行結果に基づいてエラー処理を行うことができます。

以下は、subprocess.runを使用してlsコマンドを実行する例です。

import subprocess
# lsコマンドを実行
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
# 実行結果を表示
print(result.stdout)

このコードを実行すると、カレントディレクトリのファイルリストが表示されます。

出力結果は以下のようになります。

total 0
-rw-r--r--  1 user  group  0 date time filename

subprocess.runは、シンプルでありながら強力な機能を持っているため、さまざまな場面で活用されます。

基本的な使い方

subprocess.run関数の基本的な使い方を理解するために、まずはその構文を見てみましょう。

基本的な構文は以下の通りです。

subprocess.run(args, *, stdin=None, input=None, stdout=None, stderr=None, shell=False, cwd=None, timeout=None, check=False)

引数の説明

引数名説明
args実行するコマンドとその引数をリスト形式で指定します。
stdin標準入力を指定します。
stdout標準出力を指定します。
stderr標準エラー出力を指定します。
shellTrueに設定すると、シェルを介してコマンドを実行します。
checkTrueに設定すると、コマンドが失敗した場合に例外を発生させます。

シンプルな例

以下は、echoコマンドを使用して文字列を表示するシンプルな例です。

import subprocess
# echoコマンドを実行
result = subprocess.run(['echo', 'Hello, World!'], capture_output=True, text=True)
# 実行結果を表示
print(result.stdout)
Hello, World!

注意点

  • argsには、コマンド名とその引数をリスト形式で指定する必要があります。
  • capture_output=Trueを指定することで、標準出力と標準エラー出力をキャプチャできます。
  • text=Trueを指定すると、出力がバイナリではなく文字列として取得できます。

このように、subprocess.runを使うことで、外部コマンドを簡単に実行し、その結果を取得することができます。

オプションの活用方法

subprocess.run関数には、コマンドの実行を制御するためのさまざまなオプションがあります。

これらのオプションを活用することで、より柔軟に外部コマンドを実行することができます。

以下に、主なオプションの使い方を紹介します。

checkオプション

checkオプションをTrueに設定すると、コマンドが失敗した場合にCalledProcessError例外が発生します。

これにより、エラーハンドリングが容易になります。

import subprocess
try:
    # 存在しないコマンドを実行
    result = subprocess.run(['nonexistent_command'], check=True)
except subprocess.CalledProcessError as e:
    print(f"エラーが発生しました: {e}")

cwdオプション

cwdオプションを使用すると、コマンドを実行する作業ディレクトリを指定できます。

import subprocess
# 特定のディレクトリでlsコマンドを実行
result = subprocess.run(['ls'], cwd='/path/to/directory', capture_output=True, text=True)
# 実行結果を表示
print(result.stdout)

shellオプション

shellオプションをTrueに設定すると、シェルを介してコマンドを実行できます。

これにより、パイプやリダイレクトなどのシェル機能を利用できます。

import subprocess
# シェルを介してコマンドを実行
result = subprocess.run('echo Hello, World! | tr " " "-"', shell=True, capture_output=True, text=True)
# 実行結果を表示
print(result.stdout)

inputオプション

inputオプションを使用すると、コマンドに標準入力を渡すことができます。

import subprocess
# echoコマンドに標準入力を渡す
result = subprocess.run(['cat'], input='Hello, World!', capture_output=True, text=True)
# 実行結果を表示
print(result.stdout)

timeoutオプション

timeoutオプションを指定すると、コマンドの実行時間に制限を設けることができます。

指定した時間内にコマンドが終了しない場合、TimeoutExpired例外が発生します。

import subprocess
try:
    # 長時間実行されるコマンドを実行(例としてsleepを使用)
    result = subprocess.run(['sleep', '10'], timeout=5)
except subprocess.TimeoutExpired:
    print("コマンドがタイムアウトしました。")

これらのオプションを活用することで、subprocess.run関数をより効果的に利用できるようになります。

状況に応じて適切なオプションを選択し、外部コマンドの実行を制御しましょう。

標準入出力の操作

subprocess.run関数を使用すると、外部コマンドの標準入出力を簡単に操作できます。

これにより、コマンドの出力を取得したり、コマンドに入力を渡したりすることが可能です。

以下に、標準入出力の操作方法を詳しく説明します。

標準出力の取得

コマンドの標準出力を取得するには、capture_output=Trueを指定します。

これにより、コマンドの出力をresult.stdoutで取得できます。

import subprocess
# lsコマンドを実行し、出力を取得
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
# 実行結果を表示
print("標準")
print(result.stdout)

このコードを実行すると、カレントディレクトリのファイルリストが表示されます。

標準エラー出力の取得

コマンドの標準エラー出力を取得するには、stderr=subprocess.PIPEを指定します。

これにより、エラー出力をresult.stderrで取得できます。

import subprocess
# 存在しないコマンドを実行し、エラー出力を取得
result = subprocess.run(['nonexistent_command'], capture_output=True, text=True)
# エラー出力を表示
print("標準エラー")
print(result.stderr)

このコードを実行すると、エラーメッセージが表示されます。

標準入力の操作

コマンドに標準入力を渡すには、inputオプションを使用します。

以下の例では、echoコマンドに文字列を渡しています。

import subprocess
# echoコマンドに標準入力を渡す
result = subprocess.run(['cat'], input='Hello, World!', capture_output=True, text=True)
# 実行結果を表示
print("標準")
print(result.stdout)

このコードを実行すると、Hello, World!という文字列が表示されます。

標準入出力のリダイレクト

標準入出力をファイルにリダイレクトすることも可能です。

以下の例では、lsコマンドの出力をファイルに保存しています。

import subprocess
# lsコマンドの出力をファイルにリダイレクト
with open('output.txt', 'w') as f:
    subprocess.run(['ls', '-l'], stdout=f)
print("lsコマンドの出力がoutput.txtに保存されました。")

このコードを実行すると、カレントディレクトリのファイルリストがoutput.txtに保存されます。

subprocess.runを使用することで、外部コマンドの標準入出力を簡単に操作できます。

標準出力や標準エラー出力を取得したり、コマンドに入力を渡したりすることで、さまざまな用途に応じたプログラムを作成することが可能です。

実行結果の確認とエラーハンドリング

subprocess.run関数を使用する際には、コマンドの実行結果を確認し、エラーが発生した場合に適切に対処することが重要です。

以下に、実行結果の確認方法とエラーハンドリングの手法を説明します。

実行結果の確認

subprocess.run関数は、実行結果を含むCompletedProcessオブジェクトを返します。

このオブジェクトには、以下の属性が含まれています。

  • returncode: コマンドの終了コード。

0は成功、0以外はエラーを示します。

  • stdout: コマンドの標準出力。
  • stderr: コマンドの標準エラー出力。

以下の例では、コマンドの実行結果を確認し、終了コードに基づいてメッセージを表示します。

import subprocess
# lsコマンドを実行
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
# 実行結果の確認
if result.returncode == 0:
    print("コマンドは成功しました。")
    print("標準")
    print(result.stdout)
else:
    print("コマンドは失敗しました。")
    print("標準エラー")
    print(result.stderr)

エラーハンドリング

checkオプションを使用すると、コマンドが失敗した場合に自動的に例外が発生します。

これにより、エラーハンドリングが簡単になります。

以下の例では、check=Trueを指定してコマンドを実行し、エラーが発生した場合に例外をキャッチします。

import subprocess
try:
    # 存在しないコマンドを実行
    result = subprocess.run(['nonexistent_command'], check=True, capture_output=True, text=True)
except subprocess.CalledProcessError as e:
    print(f"エラーが発生しました: {e}")
    print("標準エラー")
    print(e.stderr)

このコードを実行すると、存在しないコマンドに対してエラーメッセージが表示されます。

エラーの詳細情報

CalledProcessError例外には、エラーが発生したコマンドの情報が含まれています。

以下の属性を使用して、エラーの詳細を取得できます。

  • cmd: 実行したコマンド。
  • returncode: 終了コード。
  • output: 標準出力。
  • stderr: 標準エラー出力。

以下の例では、エラーの詳細情報を表示します。

import subprocess
try:
    # 存在しないコマンドを実行
    result = subprocess.run(['nonexistent_command'], check=True, capture_output=True, text=True)
except subprocess.CalledProcessError as e:
    print(f"コマンド: {e.cmd}")
    print(f"終了コード: {e.returncode}")
    print("標準エラー")
    print(e.stderr)

subprocess.runを使用する際には、実行結果を確認し、エラーが発生した場合に適切に対処することが重要です。

returncodeを確認することで成功・失敗を判断し、checkオプションを利用することでエラーハンドリングを簡素化できます。

これにより、より堅牢なプログラムを作成することが可能になります。

応用的な使い方

subprocess.run関数は、基本的なコマンド実行だけでなく、さまざまな応用的な使い方が可能です。

ここでは、いくつかの応用例を紹介します。

複数のコマンドをパイプで接続

シェルのパイプ機能を利用して、複数のコマンドを接続することができます。

shell=Trueを指定することで、シェルを介してコマンドを実行できます。

以下の例では、lsコマンドの出力をgrepコマンドでフィルタリングしています。

import subprocess
# lsコマンドの出力をgrepでフィルタリング
result = subprocess.run('ls -l | grep ".py"', shell=True, capture_output=True, text=True)
# 実行結果を表示
print("Pythonファイル:")
print(result.stdout)

環境変数の設定

envオプションを使用すると、コマンドを実行する際の環境変数を設定できます。

以下の例では、MY_VARという環境変数を設定してコマンドを実行しています。

import subprocess
import os
# 環境変数を設定
my_env = os.environ.copy()
my_env['MY_VAR'] = 'Hello, World!'
# 環境変数を使用してechoコマンドを実行
result = subprocess.run(['echo', '$MY_VAR'], env=my_env, shell=True, capture_output=True, text=True)
# 実行結果を表示
print("環境変数の")
print(result.stdout)

非同期実行

subprocess.runは同期的にコマンドを実行しますが、subprocess.Popenを使用することで非同期にコマンドを実行することができます。

以下の例では、sleepコマンドを非同期に実行し、他の処理を行っています。

import subprocess
import time
# 非同期にsleepコマンドを実行
process = subprocess.Popen(['sleep', '5'])
# 他の処理を行う
print("他の処理を実行中...")
time.sleep(2)
print("処理が完了しました。")
# コマンドの終了を待つ
process.wait()
print("sleepコマンドが完了しました。")

コマンドの出力をファイルに保存

コマンドの出力をファイルに保存することも可能です。

以下の例では、dfコマンドの出力をdisk_usage.txtというファイルに保存しています。

import subprocess
# dfコマンドの出力をファイルに保存
with open('disk_usage.txt', 'w') as f:
    subprocess.run(['df', '-h'], stdout=f)
print("ディスク使用状況がdisk_usage.txtに保存されました。")

コマンドの実行時間を計測

コマンドの実行時間を計測することもできます。

以下の例では、timeモジュールを使用してコマンドの実行時間を測定しています。

import subprocess
import time
# コマンドの実行開始時間を記録
start_time = time.time()
# sleepコマンドを実行
subprocess.run(['sleep', '3'])
# 実行時間を計測
end_time = time.time()
execution_time = end_time - start_time
print(f"コマンドの実行時間: {execution_time}秒")

subprocess.run関数は、基本的なコマンド実行だけでなく、さまざまな応用が可能です。

複数のコマンドの接続、環境変数の設定、非同期実行、出力のファイル保存、実行時間の計測など、用途に応じて柔軟に活用することができます。

これにより、より高度なスクリプトやプログラムを作成することが可能になります。

よくあるエラーとその対処法

subprocess.runを使用する際には、いくつかの一般的なエラーが発生することがあります。

ここでは、よくあるエラーとその対処法を紹介します。

FileNotFoundError

エラー内容: 指定したコマンドが見つからない場合に発生します。

対処法: コマンド名が正しいか、またはそのコマンドがシステムにインストールされているかを確認します。

パスが必要な場合は、フルパスを指定することも検討してください。

import subprocess
try:
    # 存在しないコマンドを実行
    result = subprocess.run(['nonexistent_command'], check=True)
except FileNotFoundError as e:
    print(f"エラー: {e}")

CalledProcessError

エラー内容: check=Trueを指定した場合、コマンドが非ゼロの終了コードで終了したときに発生します。

対処法: コマンドの引数や実行環境を確認し、エラーの原因を特定します。

stderrを確認することで、エラーメッセージを取得できます。

import subprocess
try:
    # 存在しないコマンドを実行
    result = subprocess.run(['ls', 'nonexistent_file'], check=True, capture_output=True, text=True)
except subprocess.CalledProcessError as e:
    print(f"エラーが発生しました: {e.stderr}")

TimeoutExpired

エラー内容: timeoutオプションを指定した場合、コマンドが指定した時間内に終了しなかったときに発生します。

対処法: コマンドの実行時間を見直し、必要に応じてtimeoutの値を調整します。

また、コマンドが長時間かかる理由を調査することも重要です。

import subprocess
try:
    # 長時間実行されるコマンドを実行
    result = subprocess.run(['sleep', '10'], timeout=5)
except subprocess.TimeoutExpired:
    print("コマンドがタイムアウトしました。")

標準出力が空

エラー内容: コマンドが正常に実行されたが、標準出力が空である場合があります。

対処法: コマンドの引数やオプションを確認し、期待する出力が得られるように修正します。

また、コマンドが実行される環境や条件も確認することが重要です。

import subprocess
result = subprocess.run(['echo'], capture_output=True, text=True)
if result.stdout.strip() == '':
    print("標準出力が空です。コマンドを確認してください。")

標準エラー出力の確認

エラー内容: コマンドが失敗した場合、標準エラー出力にエラーメッセージが表示されますが、これを見逃すことがあります。

対処法: コマンドの実行後にstderrを確認し、エラーメッセージを表示するようにします。

これにより、問題の特定が容易になります。

import subprocess
result = subprocess.run(['ls', 'nonexistent_file'], capture_output=True, text=True)
if result.returncode != 0:
    print("エラーが発生しました。")
    print("標準エラー")
    print(result.stderr)

subprocess.runを使用する際には、さまざまなエラーが発生する可能性があります。

これらのエラーを理解し、適切に対処することで、より堅牢なプログラムを作成することができます。

エラーメッセージを確認し、原因を特定することが重要です。

他のsubprocess関数との比較

Pythonのsubprocessモジュールには、subprocess.run以外にもいくつかの関数が用意されています。

それぞれの関数には異なる用途や特徴があり、状況に応じて使い分けることが重要です。

ここでは、subprocess.runと他の主要な関数との比較を行います。

subprocess.run vs subprocess.call

  • subprocess.run: コマンドを実行し、CompletedProcessオブジェクトを返します。

標準出力や標準エラー出力をキャプチャすることができ、エラーハンドリングも容易です。

  • subprocess.call: コマンドを実行し、終了コードを返します。

標準出力や標準エラー出力をキャプチャする機能はありません。

シンプルな用途に適しています。

import subprocess
# subprocess.runの例
result = subprocess.run(['ls', '-l'], capture_output=True, text=True)
print(result.stdout)
# subprocess.callの例
exit_code = subprocess.call(['ls', '-l'])
print(f"終了コード: {exit_code}")

subprocess.run vs subprocess.Popen

  • subprocess.run: コマンドを実行し、完了するまで待機します。

シンプルで使いやすいですが、非同期処理には向いていません。

  • subprocess.Popen: コマンドを非同期に実行し、プロセスオブジェクトを返します。

標準入出力のリダイレクトや、プロセスの管理が柔軟に行えます。

import subprocess
import time
# subprocess.runの例
subprocess.run(['sleep', '2'])
# subprocess.Popenの例
process = subprocess.Popen(['sleep', '2'])
print("他の処理を実行中...")
time.sleep(1)
print("処理が完了しました。")
process.wait()

subprocess.run vs subprocess.check_call / subprocess.check_output

  • subprocess.check_call: コマンドを実行し、終了コードが0でない場合にCalledProcessErrorを発生させます。

標準出力はキャプチャしません。

  • subprocess.check_output: コマンドを実行し、標準出力をキャプチャして返します。

終了コードが0でない場合はCalledProcessErrorを発生させます。

import subprocess
# subprocess.check_callの例
try:
    subprocess.check_call(['ls', 'nonexistent_file'])
except subprocess.CalledProcessError as e:
    print(f"エラーが発生しました: {e}")
# subprocess.check_outputの例
try:
    output = subprocess.check_output(['ls', '-l'], text=True)
    print(output)
except subprocess.CalledProcessError as e:
    print(f"エラーが発生しました: {e}")

subprocessモジュールには、さまざまな関数が用意されており、それぞれ異なる用途に適しています。

subprocess.runは、シンプルで使いやすいコマンド実行のための関数ですが、他の関数も状況に応じて活用することで、より柔軟なプログラムを作成することができます。

目的に応じて適切な関数を選択し、効果的に利用しましょう。

実用例

subprocess.run関数は、さまざまな実用的なシナリオで活用できます。

ここでは、いくつかの具体的な例を紹介します。

これらの例を参考にして、実際のプロジェクトに応じた使い方を考えてみましょう。

ファイルのバックアップ

特定のディレクトリ内のファイルをバックアップするために、tarコマンドを使用する例です。

以下のコードでは、指定したディレクトリを圧縮してバックアップファイルを作成します。

import subprocess
import datetime
# バックアップするディレクトリ
source_dir = '/path/to/source_directory'
# バックアップファイル名
backup_file = f'backup_{datetime.datetime.now().strftime("%Y%m%d_%H%M%S")}.tar.gz'
# tarコマンドを使用してバックアップを作成
subprocess.run(['tar', '-czf', backup_file, source_dir])
print(f"バックアップが作成されました: {backup_file}")

システム情報の取得

dfコマンドを使用して、ディスクの使用状況を取得し、標準出力に表示する例です。

import subprocess
# dfコマンドを実行
result = subprocess.run(['df', '-h'], capture_output=True, text=True)
# 実行結果を表示
print("ディスク使用状況:")
print(result.stdout)

Webページのダウンロード

curlコマンドを使用して、指定したURLからWebページをダウンロードする例です。

ダウンロードした内容はファイルに保存されます。

import subprocess
# ダウンロードするURL
url = 'https://www.example.com'
# 保存するファイル名
output_file = 'downloaded_page.html'
# curlコマンドを使用してWebページをダウンロード
subprocess.run(['curl', '-o', output_file, url])
print(f"Webページがダウンロードされました: {output_file}")

画像のリサイズ

ImageMagickを使用して、画像をリサイズする例です。

以下のコードでは、指定した画像ファイルを指定したサイズにリサイズします。

import subprocess
# リサイズする画像ファイル
input_image = 'input_image.jpg'
output_image = 'output_image.jpg'
width = 800
height = 600
# convertコマンドを使用して画像をリサイズ
subprocess.run(['convert', input_image, '-resize', f'{width}x{height}', output_image])
print(f"画像がリサイズされました: {output_image}")

プロセスの監視

psコマンドを使用して、現在実行中のプロセスを監視し、特定のプロセスが実行中かどうかを確認する例です。

import subprocess
# 実行中のプロセスを確認
process_name = 'python3'
result = subprocess.run(['pgrep', process_name], capture_output=True, text=True)
if result.stdout:
    print(f"{process_name} プロセスが実行中です。")
else:
    print(f"{process_name} プロセスは実行されていません。")

これらの実用例は、subprocess.runを使用してさまざまなタスクを自動化する方法を示しています。

ファイルのバックアップ、システム情報の取得、Webページのダウンロード、画像のリサイズ、プロセスの監視など、subprocessモジュールを活用することで、Pythonスクリプトから外部コマンドを効果的に利用できます。

これらの例を参考にして、自分のプロジェクトに応じた使い方を考えてみましょう。

まとめ

この記事では、Pythonのsubprocess.run関数を中心に、外部コマンドの実行方法やその活用法について詳しく解説しました。

subprocessモジュールの基本的な使い方から、標準入出力の操作、エラーハンドリング、応用的な使い方、実用例まで幅広く取り上げ、実際のプログラムに役立つ情報を提供しました。

これを機に、subprocessモジュールを活用して、日常のタスクを自動化したり、効率的に処理を行ったりすることに挑戦してみてください。

関連記事

Back to top button