[Python] 別のプロセス(アプリケーション)を起動する方法

Pythonで別のプロセスやアプリケーションを起動するには、標準ライブラリのsubprocessモジュールを使用します。

subprocess.run()subprocess.Popen()が一般的な方法です。

subprocess.run()はコマンドを実行し、終了するまで待機しますが、subprocess.Popen()は非同期でプロセスを開始し、すぐに制御を返します。

例えば、subprocess.run(["ls", "-l"])でLinuxのlsコマンドを実行できます。

この記事でわかること
  • subprocess.run()とsubprocess.Popen()の違い
  • プロセス間通信の実装方法
  • バックグラウンドプロセスの管理方法
  • 環境ごとの注意点
  • 外部アプリケーションの制御方法

Pythonを活用して、さまざまなプロセスを効率的に管理し、制御する手法を実践してみることをお勧めします

目次から探す

subprocess.run()を使ったプロセスの起動

Pythonのsubprocessモジュールを使用すると、外部プロセスを起動し、制御することができます。

特にsubprocess.run()は、簡単に外部コマンドを実行するための便利な関数です。

subprocess.run()の基本的な使い方

subprocess.run()は、指定したコマンドを実行し、その結果を返します。

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

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

この例では、ls -lコマンドを実行しています。

resultには、コマンドの実行結果が格納されます。

コマンドの引数を指定する方法

コマンドに引数を渡す場合、リスト形式で指定します。

以下の例では、echoコマンドを使用して文字列を出力します。

import subprocess
# 引数を指定してコマンドを実行する
result = subprocess.run(['echo', 'こんにちは、世界!'])
こんにちは、世界!

実行結果を取得する方法

subprocess.run()は、実行結果をCompletedProcessオブジェクトとして返します。

このオブジェクトから標準出力や終了コードを取得できます。

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

タイムアウトを設定する方法

コマンドの実行に時間がかかる場合、タイムアウトを設定することができます。

以下の例では、5秒のタイムアウトを設定しています。

import subprocess
try:
    # タイムアウトを設定してコマンドを実行する
    result = subprocess.run(['sleep', '10'], timeout=5)
except subprocess.TimeoutExpired:
    print("タイムアウトが発生しました。")

この場合、10秒待機するコマンドが5秒でタイムアウトします。

エラー処理の方法

コマンドが失敗した場合、subprocess.run()は例外を発生させることができます。

check=Trueを指定すると、コマンドが正常に終了しなかった場合にCalledProcessErrorが発生します。

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

この例では、存在しないコマンドを実行し、エラーが発生したことを表示します。

subprocess.Popen()を使った非同期プロセスの起動

subprocess.Popen()は、外部プロセスを非同期に起動するための関数です。

これにより、Pythonプログラムが他の処理を行っている間に、外部コマンドを実行することができます。

subprocess.Popen()の基本的な使い方

subprocess.Popen()を使用すると、プロセスを非同期に起動し、プロセスオブジェクトを取得できます。

以下の例では、pingコマンドを実行しています。

import subprocess
# プロセスを非同期に起動する
process = subprocess.Popen(['ping', '-c', '4', 'google.com'])
# プロセスオブジェクトを表示
print(process)

この例では、pingコマンドが非同期に実行され、Pythonプログラムはその後の処理を続けることができます。

非同期処理のメリットとデメリット

非同期処理には以下のようなメリットとデメリットがあります。

スクロールできます
メリットデメリット
プログラムの応答性が向上するプロセス管理が複雑になる
複数のプロセスを同時に実行可能エラー処理が難しくなることがある
リソースの効率的な利用が可能デバッグが難しくなることがある

標準入力・出力・エラーのリダイレクト

Popenを使用すると、標準入力、標準出力、標準エラーをリダイレクトすることができます。

以下の例では、grepコマンドを使用して、特定の文字列をフィルタリングします。

import subprocess
# grepコマンドを使用して文字列をフィルタリング
process = subprocess.Popen(['echo', 'Pythonは楽しい!'], stdout=subprocess.PIPE)
output, error = process.communicate()
# 結果を表示
print(output.decode())
Pythonは楽しい!

プロセスの終了を待機する方法

非同期に起動したプロセスが終了するのを待機するには、wait()メソッドを使用します。

以下の例では、sleepコマンドを実行し、その終了を待機します。

import subprocess
# sleepコマンドを実行する
process = subprocess.Popen(['sleep', '5'])
# プロセスの終了を待機する
process.wait()
print("プロセスが終了しました。")

この例では、5秒間のスリープ後に「プロセスが終了しました。」と表示されます。

プロセスの強制終了方法

実行中のプロセスを強制終了するには、terminate()メソッドを使用します。

以下の例では、sleepコマンドを強制終了します。

import subprocess
import time
# sleepコマンドを実行する
process = subprocess.Popen(['sleep', '10'])
# 2秒待機してからプロセスを強制終了する
time.sleep(2)
process.terminate()
print("プロセスを強制終了しました。")

この例では、2秒後にsleepコマンドが強制終了され、「プロセスを強制終了しました。」と表示されます。

プロセス間通信の実装

プロセス間通信(IPC)は、異なるプロセス間でデータをやり取りするための手法です。

Pythonのsubprocessモジュールを使用すると、標準入力、標準出力、パイプを利用してプロセス間でデータを送受信できます。

標準入力を使ったデータの送信

標準入力を使用してデータを送信するには、Popenstdin引数をsubprocess.PIPEに設定します。

以下の例では、echoコマンドにデータを送信しています。

import subprocess
# echoコマンドを実行し、標準入力を使用してデータを送信する
process = subprocess.Popen(['echo'], stdin=subprocess.PIPE, stdout=subprocess.PIPE, text=True)
# データを送信
output, _ = process.communicate(input='こんにちは、プロセス間通信!')
# 結果を表示
print(output)
こんにちは、プロセス間通信!

標準出力を使ったデータの受信

標準出力を使用してデータを受信するには、stdout引数をsubprocess.PIPEに設定します。

以下の例では、lsコマンドの結果を受信しています。

import subprocess
# lsコマンドを実行し、標準出力からデータを受信する
process = subprocess.Popen(['ls', '-l'], stdout=subprocess.PIPE, text=True)
# 結果を取得
output, _ = process.communicate()
# 結果を表示
print(output)

この例では、ls -lコマンドの出力が表示されます。

パイプを使ったプロセス間通信

パイプを使用すると、複数のプロセス間でデータをやり取りできます。

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

import subprocess
# echoコマンドを実行し、その出力をgrepでフィルタリングする
echo_process = subprocess.Popen(['echo', 'Pythonは楽しい!'], stdout=subprocess.PIPE)
grep_process = subprocess.Popen(['grep', '楽しい'], stdin=echo_process.stdout, stdout=subprocess.PIPE, text=True)
# echoプロセスの出力を閉じる
echo_process.stdout.close()
# grepプロセスの結果を取得
output, _ = grep_process.communicate()
# 結果を表示
print(output)
Pythonは楽しい!

複数プロセス間でのデータのやり取り

複数のプロセス間でデータをやり取りする場合、パイプを利用してデータを流すことができます。

以下の例では、wcコマンドを使用して、echoコマンドの出力行数をカウントしています。

import subprocess
# echoコマンドを実行し、その出力をwcでカウントする
echo_process = subprocess.Popen(['echo', 'Pythonは楽しい!\nPythonは素晴らしい!'], stdout=subprocess.PIPE)
wc_process = subprocess.Popen(['wc', '-l'], stdin=echo_process.stdout, stdout=subprocess.PIPE, text=True)
# echoプロセスの出力を閉じる
echo_process.stdout.close()
# wcプロセスの結果を取得
output, _ = wc_process.communicate()
# 結果を表示
print(f"行数: {output.strip()}")  # 出力結果から空白を削除
行数: 2

このように、subprocessモジュールを使用することで、プロセス間でのデータの送受信が簡単に実現できます。

実行環境に依存する注意点

Pythonのsubprocessモジュールを使用して外部プロセスを起動する際、実行環境によって注意が必要な点があります。

ここでは、Windows、Linux、MacOSそれぞれの環境での注意点と、クロスプラットフォームでの互換性を保つ方法について解説します。

Windows環境での注意点

  • コマンドの形式: Windowsでは、コマンドの形式がLinuxやMacOSとは異なる場合があります。

例えば、lsコマンドはWindowsではdirに置き換える必要があります。

  • パスの区切り文字: Windowsでは、パスの区切り文字がバックスラッシュ\であるため、ファイルパスを指定する際には注意が必要です。
  • コマンドプロンプトの使用: 一部のコマンドは、コマンドプロンプト(cmd.exe)やPowerShellでのみ動作するため、適切なシェルを選択する必要があります。

Linux環境での注意点

  • 権限の管理: Linuxでは、実行するコマンドに対して適切な権限が必要です。

特に、sudoを使用する場合は、subprocessでの実行に注意が必要です。

  • シェルの使用: シェルスクリプトを実行する場合、shell=Trueを指定する必要がありますが、セキュリティ上のリスクがあるため、注意が必要です。
  • コマンドの存在確認: 実行するコマンドがシステムにインストールされているか確認することが重要です。

MacOS環境での注意点

  • コマンドの互換性: MacOSはUnix系のOSであるため、Linuxと同様のコマンドが多く使用できますが、一部のコマンドは異なるオプションを持つことがあります。
  • Homebrewの利用: MacOSでは、Homebrewを使用してパッケージを管理することが一般的です。

必要なコマンドがインストールされているか確認することが重要です。

  • システムのバージョン: MacOSのバージョンによっては、特定のコマンドやオプションが異なる場合があるため、注意が必要です。

クロスプラットフォームでの互換性を保つ方法

  • 条件分岐を使用する: 実行環境に応じて異なるコマンドを実行するために、osモジュールを使用して条件分岐を行うことができます。
import os
import subprocess
if os.name == 'nt':  # Windows
    command = ['dir']
else:  # Linux or MacOS
    command = ['ls', '-l']
subprocess.run(command)
  • 環境変数を利用する: 環境変数を使用して、実行環境に依存する設定を管理することができます。
  • 仮想環境の利用: Pythonの仮想環境を使用することで、依存関係を管理し、異なる環境での動作を確認することができます。
  • クロスプラットフォームライブラリの利用: pathlibos.pathなどの標準ライブラリを使用して、パスの操作を行うことで、プラットフォームに依存しないコードを書くことができます。

これらの注意点を考慮することで、Pythonのsubprocessモジュールを使用したプロセスの起動がよりスムーズに行えるようになります。

応用例:外部アプリケーションの制御

Pythonのsubprocessモジュールを使用することで、外部アプリケーションを制御することができます。

ここでは、ブラウザの自動起動、シェルスクリプトの実行、他のPythonスクリプトの実行、GUIアプリケーションの起動について解説します。

ブラウザを自動で起動する

特定のURLを自動でブラウザで開くには、subprocessを使用してブラウザの実行ファイルを呼び出します。

以下の例では、Google Chromeを使用して特定のURLを開きます。

import subprocess
import webbrowser
# デフォルトのブラウザでURLを開く
url = 'https://www.example.com'
webbrowser.open(url)
# または、特定のブラウザを指定して起動する
subprocess.run(['open', '-a', 'Google Chrome', url])  # MacOSの場合
# subprocess.run(['start', 'chrome', url])  # Windowsの場合

このコードを実行すると、指定したURLがブラウザで開かれます。

シェルスクリプトを実行する

シェルスクリプトを実行するには、subprocess.run()を使用します。

以下の例では、シェルスクリプトscript.shを実行します。

import subprocess
# シェルスクリプトを実行する
result = subprocess.run(['bash', 'script.sh'], capture_output=True, text=True)
# 結果を表示
print(result.stdout)

このコードでは、script.shの実行結果が表示されます。

Pythonスクリプトから他のPythonスクリプトを実行する

Pythonスクリプトから別のPythonスクリプトを実行することも可能です。

以下の例では、other_script.pyを実行します。

import subprocess
# 他のPythonスクリプトを実行する
result = subprocess.run(['python', 'other_script.py'], capture_output=True, text=True)
# 結果を表示
print(result.stdout)

このコードを実行すると、other_script.pyの出力が表示されます。

GUIアプリケーションを起動する

GUIアプリケーションを起動するには、アプリケーションの実行ファイルを指定してsubprocess.run()を使用します。

以下の例では、メモ帳アプリケーションを起動します。

import subprocess
# メモ帳アプリケーションを起動する
subprocess.run(['notepad'])  # Windowsの場合
# subprocess.run(['open', '-a', 'TextEdit'])  # MacOSの場合

このコードを実行すると、指定したGUIアプリケーションが起動します。

これらの応用例を通じて、Pythonを使用して外部アプリケーションを制御する方法を理解することができます。

subprocessモジュールを活用することで、さまざまなタスクを自動化し、効率的に作業を進めることが可能です。

応用例:バックグラウンドプロセスの管理

Pythonのsubprocessモジュールを使用すると、バックグラウンドでプロセスを実行し、その状態やリソース使用量を管理することができます。

ここでは、バックグラウンドでのプロセス実行、プロセスの監視、終了コードの取得、リソース使用量の確認について解説します。

バックグラウンドでプロセスを実行する方法

バックグラウンドでプロセスを実行するには、subprocess.Popen()を使用します。

以下の例では、sleepコマンドをバックグラウンドで実行します。

import subprocess
# sleepコマンドをバックグラウンドで実行する
process = subprocess.Popen(['sleep', '10'])
# プロセスIDを表示
print(f"バックグラウンドプロセスのID: {process.pid}")

このコードを実行すると、sleepコマンドが10秒間バックグラウンドで実行されます。

プロセスの状態を監視する方法

バックグラウンドで実行中のプロセスの状態を監視するには、poll()メソッドを使用します。

このメソッドは、プロセスが終了しているかどうかを確認します。

import subprocess
import time
# sleepコマンドをバックグラウンドで実行する
process = subprocess.Popen(['sleep', '10'])
# プロセスの状態を監視する
while True:
    status = process.poll()
    if status is None:
        print("プロセスはまだ実行中です。")
        time.sleep(1)  # 1秒待機
    else:
        print(f"プロセスは終了しました。終了コード: {status}")
        break

このコードでは、プロセスが終了するまで状態を監視し、終了後に終了コードを表示します。

プロセスの終了コードを取得する方法

プロセスが終了した後、その終了コードを取得するには、returncode属性を使用します。

以下の例では、lsコマンドを実行し、終了コードを取得します。

import subprocess
# lsコマンドを実行する
process = subprocess.run(['ls', '-l'])
# 終了コードを表示
print(f"終了コード: {process.returncode}")

このコードを実行すると、lsコマンドの終了コードが表示されます。

正常終了の場合は0が返されます。

プロセスのリソース使用量を確認する方法

プロセスのリソース使用量を確認するには、psutilライブラリを使用することが一般的です。

以下の例では、psutilを使用してバックグラウンドプロセスのCPUとメモリ使用量を確認します。

import subprocess
import time
import psutil
# sleepコマンドをバックグラウンドで実行する
process = subprocess.Popen(['sleep', '10'])
# プロセスのリソース使用量を監視する
while True:
    try:
        p = psutil.Process(process.pid)
        cpu_usage = p.cpu_percent(interval=1)
        memory_info = p.memory_info()
        print(f"CPU使用率: {cpu_usage}%")
        print(f"メモリ使用量: {memory_info.rss / (1024 * 1024):.2f} MB")
    except psutil.NoSuchProcess:
        print("プロセスは終了しました。")
        break

このコードでは、プロセスが終了するまでCPU使用率とメモリ使用量を表示します。

psutilライブラリを使用することで、プロセスの詳細なリソース使用状況を把握することができます。

これらの応用例を通じて、Pythonを使用してバックグラウンドプロセスを管理する方法を理解することができます。

subprocessモジュールとpsutilライブラリを組み合わせることで、効率的なプロセス管理が可能になります。

よくある質問

subprocess.run()とsubprocess.Popen()の違いは?

subprocess.run()subprocess.Popen()は、どちらも外部プロセスを実行するための関数ですが、以下のような違いがあります。

  • 実行方法:
  • subprocess.run()は、指定したコマンドを実行し、プロセスが終了するまで待機します。

結果をCompletedProcessオブジェクトとして返します。

  • subprocess.Popen()は、プロセスを非同期に起動し、すぐに制御を戻します。

プロセスの状態を後で確認することができます。

  • 使い方:
  • subprocess.run()は、簡単なコマンド実行に適しており、結果をすぐに取得したい場合に便利です。
  • subprocess.Popen()は、複数のプロセスを同時に実行したり、プロセス間通信を行う場合に適しています。

プロセスが終了しない場合の対処法は?

プロセスが終了しない場合、以下の対処法があります。

  1. タイムアウトを設定する: subprocess.run()Popen()の実行時にタイムアウトを設定することで、指定した時間内にプロセスが終了しない場合に自動的に終了させることができます。
   result = subprocess.run(['some_command'], timeout=5)  # 5秒のタイムアウト
  1. プロセスの状態を監視する: poll()メソッドを使用して、プロセスの状態を定期的に確認し、必要に応じて強制終了することができます。
  2. プロセスを強制終了する: プロセスが応答しない場合、terminate()メソッドを使用して強制終了することができます。
   process.terminate()

実行中のプロセスを強制終了するには?

実行中のプロセスを強制終了するには、terminate()またはkill()メソッドを使用します。

  • terminate(): プロセスに終了シグナルを送信し、正常に終了させることを試みます。
  process.terminate()
  • kill(): プロセスを強制的に終了させます。

terminate()が効かない場合に使用します。

  process.kill()

これらのメソッドを使用することで、実行中のプロセスを適切に管理し、必要に応じて強制終了することができます。

まとめ

この記事では、Pythonのsubprocessモジュールを使用して外部プロセスを起動し、制御する方法について詳しく解説しました。

具体的には、プロセスの起動方法やプロセス間通信、バックグラウンドプロセスの管理、さらには外部アプリケーションの制御に関する実用的な例を紹介しました。

これらの知識を活用することで、Pythonを用いた自動化や効率的なタスク管理が可能になりますので、ぜひ実際のプロジェクトに応用してみてください。

  • URLをコピーしました!
目次から探す