Bashシェルでのジョブとジョブ制御
1. 概要
bash でコマンドを実行するときはいつでも、それはジョブとして実行されます。 ジョブの管理方法を理解することは、シェルをより適切に制御できることを意味します。
このチュートリアルでは、 bash にあるジョブと、それらがプロセスにどのように関連しているかを調べます。 それらをバックグラウンドで開始、一時停止、再開、および実行する方法を学習します。
2. bashシェルのプロセスとジョブ
Linuxのプロセスとは、実行中のプログラムを意味します。 たとえば、 ls を実行すると、プロセスとして実行されます。 ls -l を使用してファイル名を検索し、その結果を grep にパイプすると、実際には2つのプロセスが実行されます。
$ ls -l | grep script
-rwxr-xr-x 1 ubuntu users 18 Aug 2 21:44 myscript.sh
1つのコマンドで複数のプロセスが実行される可能性があるため、 bash シェルではジョブとして表され、単一のコマンドまたはスクリプトから実行されるプロセスの論理グループです。
3. ジョブの一時停止と再開
ls の例では、通常、実行がすぐに完了し、シェルプロンプトに戻ることを期待しています。 ただし、コマンドに時間がかかる場合は、コマンドが終了するのを待つ必要があります。 また、待機中に別のコマンドを実行する場合は、別のシェルを開く必要があります。
find コマンドを実行し、探していると思われるファイルがすでに表示されているとします。 Ctrl +Cを押してコマンドを停止できます。 ただし、検索を一時停止して、再確認し、必要に応じて再開できるようにすることをお勧めします。
Ctrl + Z を使用して、現在のジョブを一時停止できます。
$ find . -name "*.java"
./code/com/my/package/Main.java
^Z
[1]+ Stopped find . -name "*.java"
ここでは、 find コマンドを実行し、出力が表示された後、 Ctrl + Z ( ^ Z )を押しました。 ジョブを一時停止すると、ジョブ番号 [1] を示すプロンプトが表示され、停止されたことを示すメッセージが表示されました。 後で説明するように、このジョブ番号で一時停止したジョブを参照できます。
シェルがジョブがStoppedであると言っていても、実際には一時停止されており、終了されていないため、再開できることに注意してください。
findコマンドを一時停止すると、シェルプロンプトに戻り、さらにコマンドを実行します。 find 操作を再開する場合は、fgコマンドを使用できます。
$ fg
find . -name "*.java"
./code/com/my/package2/Util.java
ここで、最後に一時停止したジョブが再開され、フォアグラウンドで実行され、完了するまでシェルを拘束するか、停止するか再度一時停止するかを選択します。
4. ジョブ制御
ジョブでさらに何ができるかを理解するために、2つの長時間実行ジョブを開始し、それぞれの後に Ctrl +Zを押して一時停止します。
$ make -j4
^Z
[1]+ Stopped make -j4
$ find . -name "*.java"
^Z
[2]+ Stopped find . -name "*.java"
4.1. ジョブの一覧表示
jobsコマンドを使用してジョブを一覧表示します。
$ jobs
[1]- Stopped make -j4
[2]+ Stopped find . -name "*.java"
jobs コマンドは、最後に一時停止したジョブを + 記号でマークし、直前に停止したジョブを –記号でマークします。 fg およびその他のジョブコマンドをジョブ番号なしで使用する場合、最後に一時停止されたジョブが暗黙指定されます。
4.2. フォアグラウンドで特定の仕事を再開する
fg コマンドを使用すると、特定のジョブをそのジョブ番号で再開できます。 ジョブの名前は、開始時に出力されます。
$ fg %1
make -j4
4.3. バックグラウンドでジョブを実行する
バックグラウンドで仕事を再開することもできます。 バックグラウンドジョブは、シェルを拘束せずに実行されます。 シェル入力にはアクセスできませんが、シェルに出力することはできます。
$ bg %1
[1]+ make -j4 &
fg と同様に、 bg コマンドでジョブ番号を省略して、最後に一時停止したジョブをバックグラウンドで再開できます。
$ bg
[2]+ find . -name "*.java" &
4.4. バックグラウンドでジョブを開始する
コマンドラインの最後にアンパサンド(&)文字を追加することで、バックグラウンドプロセスとして直接ジョブを開始することもできます。
$ find . -name "*.java" &
[1] 1726
5. メッセージ:停止したジョブがあります
Ctrl + D を押すか、 logoutを使用してシェルを終了しようとすると、エラーメッセージが表示される場合があります。
$ logout
There are stopped jobs.
bash がこのメッセージを表示すると、ログアウトも防止されます。
これは、 bash では、一時停止中のジョブがある間はシェルを終了できないためです。 現在のシェルのプロセスがそのジョブを管理します。 ジョブを一時停止すると、不完全な状態のままになります。 ジョブを一時停止してシェルを終了すると、重要なデータが失われる可能性があります。
したがって、シェルを終了する前に、これらの一時停止されたジョブを処理する必要があります。
5.1. 処理するジョブを一覧表示する
私たちの仕事をどうするかを決めるために、それらをリストしましょう:
$ jobs
[1]- Stopped python
[2]+ Stopped find . -name "*.java" > javafiles.txt
これらの仕事に応じて、私たちはそれらを実行し続けるか、それらを殺したいと思うかもしれません。
5.2. ジョブを実行し続ける
バックグラウンドでジョブを実行し続ける方法については、すでに説明しました。
$ bg %2
[2]+ find . -name "*.java" > javafiles.txt &
バックグラウンドジョブについて前述したように、このジョブはバックグラウンドで実行している間もシェルに出力できます。 ここでシェルを終了すると、シェルがもう存在しないため、シェルに出力しようとすると、ジョブが終了する可能性があります。 また、特定の信号を受信したときに殺される可能性があります。
これを回避するには、disownコマンドを使用して、現在のシェルからバックグラウンドジョブを削除できます。
$ disown %2
$ logout
これにより、シェルが終了した後でも、バックグラウンドジョブがバックグラウンドで実行され続けることが保証されます。
5.3. 仕事を殺す
または、 kill コマンドを使用して、不要なジョブを強制終了することもできます。
$ kill %1
[1]+ Stopped python
$ logout
kill を使用すると、%1 をジョブ番号として使用できますが、プロセスIDによってプロセスを終了するためにも一般的に使用されます。
6. 結論
この記事では、 bash シェルが、複数のプロセスが含まれている場合でも、実行するすべてのコマンドをジョブとして処理する方法を説明しました。
ジョブを一覧表示、一時停止、再開、および強制終了する方法を学びました。
また、バックグラウンドでジョブを配置し、シェルが終了してもジョブを実行し続ける方法についても説明しました。