CTC 教育サービス
[IT研修]注目キーワード Python UiPath(RPA) 最新技術動向 Microsoft Azure Docker Kubernetes
前回は、シグナルについて説明しました。今回は、bashのジョブとそのコントロール方法について説明します。
ジョブコントロール(またはジョブ制御)は、プロセスの実行を選択的に一時停止(サスペンド=suspend)、実行再開(レジューム=resume)する機能です。通常ログイン時にbashを使う際、対話的インタフェースを通してジョブコントールを行います。対話的インタフェースは、カーネル(OSの中枢部分)が提供する端末(ターミナルドライバ)とbashの組合せで実現されます。ジョブは、端末から実行されたプロセスを抽象化したものです。
カーネルは、現在の端末プロセスグループID(current terminal process group ID)という情報を管理しています。ある端末から実行したプロセスは、同じ端末プロセスグループに含まれ、端末からキーボードを経由したシグナルを受け取ります。このプロセスをフォアグラウンドプロセスと呼びます。バックグラウンドプロセスは、プロセスの端末グループ ID が端末グループ ID と異なるプロセスです。 このようなプロセスは、キーボードで生成したシグナルの影響を受けず、kill
コマンドを使用してシグナルを送信する必要があります。フォアグラウンドプロセスは端末からの読み込みが許可されますが、バックグラウンドプロセスは許可されません。バックグラウンドプロセスへ端末からの読み込みを実行しようとすると、端末からプロセスに対しシグナルSIGTTIN(もしくはSIGTTOU)が送られます。プロセスがこのシグナルを補足しない場合、プロセスは停止します。
フォアグラウンドジョブとバックグラウンドジョブは、フォアグラウンドプロセスとなります。通常コマンド実行しようとするとフォアグラウンドジョブとなります。末尾に"&"をつけると、非同期にジョブが実行され、バックグラウンドジョブと呼ばれます。ただしバックグラウンドジョブはフォアグラウンドプロセスで、端末終了時にプロセスが停止すること注意してください。
指定された時間待機するコマンドsleepを使用して、フォアグラウンドジョブとバックグラウンドジョブを確認します。
# jobsを実行し、何も表示されない(バックグラウンドジョブがない)ことを確認
$ jobs
# sleep を3600秒指定して実行
$ sleep 3600
# ここでCtrl-Zを入力し、サスペンドする
^Z
[1]+ Stopped sleep 3600
# jobsを実行し、バックグラウンドジョブが表示されることを確認
$ jobs
[1]+ Stopped sleep 3600
# 末尾に&をつけて、バックグラウンドジョブを実行する(プロセスIDが表示される)
$ sleep 1800 &
[2] 3023
# jobsを実行し、バックグラウンドジョブが表示されることを確認(-lオプションでプロセス番号を表示)
$ jobs -l
[1]+ 3016 Stopped sleep 3600
[2]- 3023 Running sleep 1800 &
sleep
コマンドを実行中に Ctrl-Z を入力すると、端末からシグナルがジョブに送信されます。そして、実行中のフォアグラウンドジョブを一時停止して、bashに制御を戻します。一時停止することで、フォアグラウンドジョブをバックグラウンドジョブとして扱い、Stopped(停止中)の状態にします。
末尾に"&"をつけるとバックグラウンドジョブとして実行され、そのプロセスIDが表示されます。
バックグラウンドジョブを確認するには、jobs
コマンドを使用します。jobs
コマンドを使用すると、[ジョブID] 状態 コマンド名
が表示されます。ジョブIDは、1から始まる整数で、バックグラウンドジョブに対してつけられます。jobs -l
を使用すると、更にプロセスIDも表示します。
フォアグラウンドジョブを一時停止するには、Ctrl-Zを使用します。ただし、Ctrl-Zを使用すると即座に停止するため、端末からの入出力する文字が一部破棄されるなどの問題が発生します。Ctrl-Yを入力すると、プロセスは遅延一時停止(delayed suspend)を行います。遅延一時停止は端末からの入力が行われようとしたタイミングで処理を一時停止し、bashに制御を戻します。
バックグラウンドジョブは、ジョブ識別子で参照できます。 %ID
は、ジョブIDを指します。%?文字列
を使用すると、「文字列」が含まれるジョブを指します。%%
、%+
はカレントジョブ(フォアグラウンドジョブを停止したものか、バックグラウンドで起動された最後のジョブ)として使用されます。%-
は、前のジョブを指します。
ジョブをフォアグラウンドジョブへ戻すには、fg
コマンドを使用します。ジョブをバックグラウンドとして再開させるにはbg
コマンドを使用します。
fg
、bg
コマンドは、ともに%
で始まるジョブ識別子を指定します。また、killコマンドもこのジョブ識別子を使用でき、プロセスを終了することができます。
# ジョブを確認
$ jobs
[1]+ 3016 Stopped sleep 3600
[2]- 3023 Running sleep 1800 &
# カレントジョブをバックグラウンドジョブとして実行する
$ bg %
[1]+ sleep 3600 &
$ jobs
[1]- Running sleep 3600 &
[2]+ Running sleep 1800 &
# ジョブ1をフォアグラウンドで実行し、サスペンドする
$ fg %1
sleep 3600
^Z
[1]+ Stopped sleep 3600
$ jobs
[1]+ Stopped sleep 3600
[2]- Running sleep 1800 &
# すべてのジョブを終了する
$ kill %
[1] Terminated sleep 3600
$ kill %2
[2]+ Terminated sleep 1800
バックグラウンドジョブはバックグラウンドプロセスではなく、フォアグラウンドプロセスです。そのため、デフォルトでは端末終了時にバックグラウンドジョブを停止します。バックグラウンドプロセスにするには、2種類の方法があります。
1つ目は、disown
コマンドを使用して既存のバックグラウンドジョブがSIGHUPを受け取らないようにすることで、バックグラウンドプロセス化することです。
2つ目は、予めnohup
コマンドを経由したコマンド実行です。nohup
コマンドは、SIGHUPを無視してプロセス実行を行うコマンドで、ファイルnohup.out
に標準出力の結果を出力します。
# disownの例
$ jobs
[1]+ Stopped sleep 3600
[2]- Running sleep 1800 &
$ disown %1
-bash: warning: deleting stopped job 1 with process group 3162
# nohupの例
$ nohup sh -c 'sleep 50 ; echo abcdef' &
# ここで端末終了し、別端末で確認
# sleep プロセスが端末終了しても継続している
$ ps -aef | grep sleep
s-miyaza 3166 1 0 18:57 ? 00:00:00 sleep 1800
s-miyaza 3232 1 0 19:01 ? 00:00:00 sh -c sleep 50 ; echo abcdef
s-miyaza 3235 3232 0 19:01 ? 00:00:00 sleep 50
今回は、bashのジョブとそのコントロール方法について説明しました。複数ターミナルを多用する現在では、ジョブコントロールの使用率は少なくなっています。しかし、簡単に一時停止できるバックグラウンドジョブや、バックグラウンドプロセスにする方法は今でも有用な手段です。次回は、bashからは離れますが、今回言及した端末について説明します。次回をお楽しみに。
[IT研修]注目キーワード Python UiPath(RPA) 最新技術動向 Microsoft Azure Docker Kubernetes