Try   HackMD

ジョブ制御ってなに? - シェルもどきをgoで自作する#18

おさらい

これまで

シェルもどき「oreshell」を自作している。
前回は、Unix(とその眷属)のシェルにおけるジョブとは何かについて調べた。
今回はジョブ制御とその仕組みについて調べる。

ジョブ制御とは

ジョブは3つの状態を持つ。

  • フォアグラウンド実行
  • バックグラウンド実行
  • 停止

これら3つの状態への切り替え、現在の状態の確認をジョブ制御で行う。

bashではジョブの現在の状態の確認は内部コマンド「jobs」で行う。
以下はその例。

$ ping yahoo.co.jp > /dev/null &
[1] 2573
$ jobs
[1]+  実行中               ping yahoo.co.jp > /dev/null &

bashではジョブの実行状態の切り替えを内部コマンド「fg」「bg」で行う。
また、端末からは「Ctrl+Z」「Ctrl+C」の入力によりジョブの実行状態を切り替える。

状態遷移図を以下に示す。

        
      

(他にも状態を切り替える方法(killコマンドなど)はあるがここでは割愛)

実行例

状態遷移図のイベントa~gを実行してみる。

まずbash内部コマンドjobsを実行してジョブの状態を確認する。

$ jobs
$

現時点では、このbash上にジョブは一つも存在しない。

a)任意の外部コマンドを実行

$ ping yahoo.co.jp
PING yahoo.co.jp (182.22.25.124) 56(84) バイトのデータ
64 バイト応答 送信元 182.22.25.124 (182.22.25.124): icmp_seq=1 ttl=56 時間=11.3ミリ秒
64 バイト応答 送信元 182.22.25.124 (182.22.25.124): icmp_seq=2 ttl=56 時間=11.4ミリ秒
...

ここではpingコマンドを実行する。実行するとpingが繰り返し実行し、結果を永久に標準出力する。

b)端末から「Ctrl+Z」を入力

...
64 バイト応答 送信元 182.22.25.124 (182.22.25.124): icmp_seq=1 ttl=56 時間=11.3ミリ秒
64 バイト応答 送信元 182.22.25.124 (182.22.25.124): icmp_seq=2 ttl=56 時間=11.4ミリ秒
(Ctrl+Zを入力)
^Z
[1]+  停止                  ping yahoo.co.jp
$

端末に「Ctrl+Z」を入力すると、先に実行したpingコマンドが停止する。

ここでbash内部コマンドjobsを実行してジョブの状態を確認する。

$ jobs
[1]+  停止                  ping yahoo.co.jp

ジョブが1つ存在する。ジョブ番号は1番、内容は「ping yahoo.co.jp」、状態は「停止」。

c)bash内部コマンドfg %{ジョブ番号}を実行

$ fg %1
ping yahoo.co.jp
64 バイト応答 送信元 182.22.25.124 (182.22.25.124): icmp_seq=5 ttl=56 時間=11.5ミリ秒
64 バイト応答 送信元 182.22.25.124 (182.22.25.124): icmp_seq=6 ttl=56 時間=12.8ミリ秒

ジョブ番号1番を指定してbash内部コマンド「fg」を実行すると、停止していたジョブ番号1番の「ping yahoo.co.jp」が実行を再開する。

d)コマンド実行終了、または端末から「Ctrl+C」を入力

...
64 バイト応答 送信元 182.22.25.124 (182.22.25.124): icmp_seq=10 ttl=56 時間=10.9ミリ秒
64 バイト応答 送信元 182.22.25.124 (182.22.25.124): icmp_seq=11 ttl=56 時間=11.7ミリ秒
(Ctrl+Cを入力)
^C
--- yahoo.co.jp ping 統計 ---
送信パケット数 11, 受信パケット数 11, パケット損失 0%, 時間 496064ミリ秒
rtt 最小/平均/最大/mdev = 10.944/11.471/12.822/0.593ミリ秒

端末に「Ctrl+C」を入力すると、pingコマンドが強制終了した。

e)任意の外部コマンドを末尾に「&」をつけて実行

$ ping yahoo.co.jp &
[1] 4842
$ PING yahoo.co.jp (183.79.248.252) 56(84) バイトのデータ
64 バイト応答 送信元 183.79.248.252 (183.79.248.252): icmp_seq=1 ttl=56 時間=4.36ミリ秒
64 バイト応答 送信元 183.79.248.252 (183.79.248.252): icmp_seq=2 ttl=56 時間=4.56ミリ秒
...

pingコマンドを末尾に「&」をつけて実行する。
実行するとこのジョブが1番であることを表示する。
その後pingが繰り返し実行し、結果を永久に標準出力する。
a)の場合と違って、ここで端末から「Ctrl+Z」や「Ctrl+C」を入力してもこのpingを停止したり強制終了することはできない。これはこのpingがバックグラウンドジョブであるため。

f)bash内部コマンドfg %{ジョブ番号}を実行

...
64 バイト応答 送信元 183.79.248.252 (183.79.248.252): icmp_seq=2 ttl=56 時間=4.56ミリ秒
$ fg %1
ping yahoo.co.jp
64 バイト応答 送信元 182.22.16.123 (182.22.16.123): icmp_seq=8 ttl=53 時間=11.4ミリ秒
64 バイト応答 送信元 182.22.16.123 (182.22.16.123): icmp_seq=9 ttl=53 時間=11.4ミリ秒

ジョブ番号1番を指定してbash内部コマンド「fg」を実行すると、バックグラウンドジョブのpingがフォアグラウンドジョブに切り替わる。
相変わらずpingの結果を標準出力し続ける。

g)bash内部コマンドbg %{ジョブ番号}を実行

^Z
[1]+  停止                  ping yahoo.co.jp

一旦、「Ctrl+Z」で停止する。

その後、

$ bg %1
bg %1
[1]+ ping yahoo.co.jp &
$ 64 バイト応答 送信元 183.79.249.252 (183.79.249.252): icmp_seq=16 ttl=56 時間=3.02ミリ秒
64 バイト応答 送信元 183.79.249.252 (183.79.249.252): icmp_seq=17 ttl=56 時間=3.06ミリ秒
...

ジョブ番号1番を指定してbash内部コマンド「bg」を実行する。実行するとこのジョブが1番であることを表示する。
その後pingがバックグラウンドジョブとして実行を再開する。

このpingで確認したいことは終わったのでf),d)で強制終了する。(f,d)

$ fg %1
(Ctrl+C)

h)コマンド実行終了

$ ping -c 3 yahoo.co.jp &
[1] 16268
$ PING yahoo.co.jp (183.79.219.252) 56(84) バイトのデータ
64 バイト応答 送信元 183.79.219.252 (183.79.219.252): icmp_seq=1 ttl=53 時間=5.28ミリ秒
64 バイト応答 送信元 183.79.219.252 (183.79.219.252): icmp_seq=2 ttl=53 時間=3.47ミリ秒
64 バイト応答 送信元 183.79.219.252 (183.79.219.252): icmp_seq=3 ttl=53 時間=3.15ミリ秒

--- yahoo.co.jp ping 統計 ---
送信パケット数 3, 受信パケット数 3, パケット損失 0%, 時間 2111ミリ秒
rtt 最小/平均/最大/mdev = 3.153/3.967/5.281/0.937ミリ秒

今度はpingを回数を指定する。コマンド末尾に「&」をつけて実行する。
pingが指定回数だけ処理を実行すると終了する。

この状態でエンターキーを押すとジョブの終了を表示する。

[1]+  終了                  ping -c 3 yahoo.co.jp

ジョブに対して「何か」を送るとジョブの実行状態が切り替わる

今度は状態遷移図ではなくロバストネス図で考えてみる。
ここではキーボードからはじまり、実行中または停止中のジョブまでの間のリクエストの伝播に絞って考える。

ジョブ実行中

        
      

端末からCtrl+Zを入力するとジョブは停止状態になる。(状態遷移図のb)
端末からCtrl+Cを入力するとジョブは終了する。(状態遷移図のd)

ジョブ停止中

        
      

bash内部コマンド「fg %1」を実行するとジョブはフォアグラウンドで実行を再開する。(状態遷移図のc)
bash内部コマンド「bg %1」を実行するとジョブはバックグラウンドで実行を再開する。(状態遷移図のg)

「何か」の正体

端末、またはbashからジョブに向けて「何か」が送られている。
この「何か」の正体は「シグナル」である。

次回はシグナルの話。