Bash 入門

Bash のプロセス管理

プロセスをバックグラウンドで実行することは、Bashユーザーにとって必須の基本スキルです。特にタスクのオートメーションや、完了までに時間がかかる操作を管理する際に重要となります。これにより、プロセスがバックグラウンドで独立して実行されている間も、ターミナルで別の作業を続行できるようになります。

これらのバックグラウンドプロセスの制御、ステータスのモニタリング、およびライフサイクルの管理方法を理解することは、効率的なシステム管理やスクリプト作成において極めて重要です。本章では、プロセスをバックグラウンドで実行し、効果的に管理するメカニズムを深く掘り下げ、より高度な自動化技術を学ぶための基礎を築きます。

1. プロセスのバックグラウンド実行の基礎

プロセスをバックグラウンドで実行するということは、そのプロセスを起動した直後にターミナルの制御権がユーザーに返されることを意味します。これにより、バックグラウンドプロセスが実行を続けている間、他のコマンドを実行することが可能になります。

1.1 & オペレーターの使用

アンパサンド(&)は、プロセスをバックグラウンドで実行させる最も一般的な方法です。コマンドの末尾にこれを追加するだけで実行できます。

# このコマンドはバックグラウンドで 'sleep' コマンドを起動します。
sleep 60 &

このコマンドを実行すると、Bashはジョブ ID(Job ID)プロセス ID(PID)を表示します。

[1] 12345
  • [1] はジョブ ID です。Bashはこれを使用してバックグラウンドジョブを追跡します。
  • 12345 は PID(プロセス ID)です。これはオペレーティングシステムがそのプロセスに割り当てた一意の識別子です。

例: 重いファイルを圧縮したいが、圧縮が完了するまで待たずに作業を続けたい場合、gzip を次のように使用できます。

gzip large_file.txt &

gzip コマンドはバックグラウンドで large_file.txt を圧縮し、その間もターミナルを使い続けることができます。

例: PythonのシンプルなWebサーバーなど、長時間実行されるサーバーアプリケーションを起動する場合、バックグラウンドで実行させることができます。

python -m http.server 8000 &

これにより、Webサーバーが現在のターミナルセッションを占有することなく稼働します。

1.2 重要な注意事項

  • 出力の干渉: デフォルトでは、バックグラウンドプロセスは依然としてターミナルに出力を書き込みます。プロセスが大量の出力を生成する場合、通常の操作の邪魔になることがあります。これを避けるには、出力をファイルにリダイレクトします(詳細は後述)。
  • ターミナルへの依存性: この方法で起動されたバックグラウンドプロセスは、依然として現在のターミナルセッションに紐付いています。ターミナルを閉じると、通常そのプロセスは終了してしまいます(nohupdisown を使用しない限り。これについては後ほど解説します)。

2. バックグラウンドプロセスの入出力リダイレクト

バックグラウンドプロセスは通常、入力を必要としたり出力を生成したりします。これらのデータフローを管理して、ターミナルセッションを妨げたり、貴重な情報を失ったりしないようにすることが重要です。

2.1 標準出力と標準エラー出力のリダイレクト

標準出力(stdout)と標準エラー出力(stderr)をファイルにリダイレクトできます。

# 標準出力を output.log に、標準エラー出力を error.log にリダイレクトします。
long_running_command > output.log 2> error.log &

# 標準出力と標準エラー出力をまとめて combined.log にリダイレクトします。
long_running_command &> combined.log &

# 標準出力と標準エラー出力を破棄します。
long_running_command > /dev/null 2>&1 &

例: データ処理スクリプトをバックグラウンドで実行する場合を考えます。出力とエラーメッセージをキャプチャしておきたいでしょう。

./process_data.sh > data_output.log 2> data_errors.log &

これにより、すべての出力とエラーが記録され、後で確認できるようになります。

例: 確認する必要のない冗長な出力を大量に生成することがわかっているコマンドを実行する場合は、それを破棄できます。

ping google.com > /dev/null 2>&1 &

これにより、ping はバックグラウンドで実行されますが、ターミナルには何も表示されません。

3. ターミナル終了後もプロセスを継続させる方法

3.1 nohup コマンドの使用

nohup コマンドは、ターミナルセッションが終了してもプロセスが強制終了(ハングアップ)されるのを防ぎます。また、自動的に標準出力と標準エラー出力を nohup.out というファイル(または指定したファイル)にリダイレクトします。

# ターミナルを閉じても継続して実行されるコマンドを実行します。
nohup long_running_command > output.log 2> error.log &

例:wget を使って大きなファイルの転送を開始するとします。

nohup wget https://example.com/large_file.zip &

ターミナルを閉じても、ダウンロードはバックグラウンドで続行されます。出力情報(明示的にリダイレクトしていない場合)は nohup.out に保存されます。

3.2 disown コマンドの使用

disown コマンドは、シェルが管理するジョブリストから特定のジョブを削除します。これにより、ターミナルを閉じてもプロセスに SIGHUP シグナルが送信されなくなり、プロセスの終了を防ぐことができます。

まず、バックグラウンドでプロセスを起動します。

sleep 60 &

次に、ジョブ ID を指定して disown コマンドを実行します。

disown %1  # ジョブ ID 1 のジョブを削除します。'jobs' コマンドで ID を確認できます。

または、最後にバックグラウンドに入れたジョブを直接削除します。

disown

例: すでにバックグラウンドで実行中のスクリプトがあるとします。

./my_backup_script.sh &

急にターミナルを閉じる必要が出てきたが、バックアップタスクは完了させたい場合、jobs コマンドでそのジョブの ID(例: [1])を確認し、以下を実行します。

disown %1

これで安全にターミナルを閉じることができます。

4. バックグラウンドプロセスのモニタリング

バックグラウンドプロセスが正常に動作していることを確認し、システムリソースを管理するためには、モニタリングが不可欠です。

4.1 jobs コマンド

jobs コマンドは、現在のターミナルセッションでアクティブなバックグラウンドジョブを一覧表示します。

jobs

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

[1]+ Running                 sleep 60 &
[2]- Stopped (signal)      vim large_file.txt
  • [1][2] はジョブ ID です。
  • RunningStopped はジョブの現在のステータスを示します。
  • sleep 60 & や vim large_file.txt は実行されているコマンドです。vim が停止(Stopped)しているのは、おそらく Ctrl+Z を押したためです。

4.2 ps コマンド

ps コマンドは、現在実行中のプロセスのスナップショットを提供します。jobs よりも詳細な情報が得られます。通常は grep と組み合わせて出力をフィルタリングします。

ps aux | grep sleep

これにより、コマンド名に "sleep" が含まれるすべてのプロセスが表示されます。aux オプションを使用すると、プロセスの実行ユーザー、PID、CPU 使用率、メモリ使用率、コマンド名などの豊富な情報が得られます。

例: process_data.sh スクリプトがまだバックグラウンドで動いているか確認したい場合。

ps aux | grep process_data.sh

これにより、そのプロセスのステータス、CPU使用率、メモリ消費量が表示されます。

4.3 top と htop コマンド

tophtop は、リアルタイムで更新されるインタラクティブなプロセスビューアです。CPUやメモリの使用状況と、実行中のプロセスリストを表示します。htoptop をより使いやすく拡張したバージョンです。

例: バックグラウンドプロセスがリソースを消費しすぎている疑いがある場合、tophtop を実行して、CPU使用率が最も高いプロセスを探します。その後、さらに調査を行うか、必要に応じてそのプロセスを終了(次節で解説)させることができます。

5. バックグラウンドプロセスの管理と制御

プロセスがバックグラウンドで実行された後、それをフォアグラウンドに戻したり、一時停止したり、あるいは強制終了したりする必要が生じることがあります。

5.1 プロセスをフォアグラウンドに戻す

fg コマンドは、バックグラウンドジョブをフォアグラウンド(最前面)に持ってきます。ジョブ ID を指定できます。

fg %1  # ジョブ ID 1 をフォアグラウンドに戻します

ジョブ ID を省略した場合、fg は最後にバックグラウンドに送られたジョブをフォアグラウンドに戻します。

fg

例:vim でファイルを編集していて、一旦作業を中断(Ctrl+Z)したとします。

vim my_file.txt
[1]+  Stopped                 vim my_file.txt

フォアグラウンドで編集を再開するには、次のように入力します。

fg %1

5.2 プロセスのポーズ(一時停止)

実行中のプロセスを停止させるには、kill コマンドに -STOP シグナルを指定するか、プロセスがフォアグラウンドにあるときに Ctrl+Z を押します。プロセスを停止させると、実行は一時停止されますが、終了はしません。後で再開することが可能です。

kill -STOP 12345 # 12345 を停止させたいプロセスの PID に置き換えてください。

これにより、指定したプロセスに STOP シグナルが送信され、実行が一時停止されます。

停止したプロセスをバックグラウンドで再開するには、bg を使用します。

bg %1 # ジョブ ID 1 をバックグラウンドで再開します

停止したプロセスをフォアグラウンドで再開するには、fg を使用します。

fg %1 # ジョブ ID 1 をフォアグラウンドで再開します

例: 長時間実行される計算タスクが CPU を使いすぎている場合、一時的に停止させることができます。

kill -STOP 12345

後でリソースに余裕ができたときに、バックグラウンドで再開させることができます。

kill -CONT 12345

5.3 プロセスの終了

kill コマンドはプロセスにシグナルを送信します。デフォルトのシグナルは TERM(終了)で、プロセスに対してクリーンアップを行ってから終了するように要求します。プロセスが TERM に反応しない場合は、KILL(シグナル 9)を使用して強制終了させることができます。

kill 12345  # TERM シグナルを送信
kill -9 12345 # KILL シグナルを送信(最終手段として使用)

例: 異常な動作をしているスクリプトが無限ループに陥った場合。まず、正常な終了を試みます。

kill 12345

しばらく待っても反応がない場合は、KILL シグナルを使用します。

kill -9 12345

5.4 重要な注意事項

  • シグナル (Signals): プロセスには多くの異なるシグナルを送信できます。一般的なものには HUP(ハングアップ)、INT(割り込み)、USR1USR2(ユーザー定義シグナル)などがあります。
  • 権限: シグナルを送信できるのは、自分が所有しているプロセス(自分のユーザーアカウントで実行されているプロセス)のみです。他人のプロセスを操作するには root 権限(sudo)が必要です。