1. 概要

完了するまでに長い時間がかかる場合があるため、バックグラウンドでコマンドを実行することがあります。 通常、バックグラウンドジョブの実行中にログアウトすると、ジョブは終了します。 ただし、 nohup コマンドを使用して、ログアウトしても実行を継続するジョブを実行できます。

後で、ログアウトして再度ログインした後、バックグラウンドで開始したプロセスのプロセス識別子( PID )を取得する必要がある場合があります。 たとえば、それがまだ実行されているかどうかを確認したい場合があります。

このチュートリアルでは、バックグラウンドプロセスのPIDをnohupで開始する方法を説明します。 nohup に関連しているため、shoptコマンドのhuponexitオプションについても触れます。

2. nohupコマンドで実行されたプロセスのPIDを取得する

nohup を使用して、バックグラウンドでプロセスを開始しましょう。

$ bash -l
$ nohup sleep infinity >& nohup.out &
[1] 20634
$ exit
logout
$

まず、bashコマンドを使用してインタラクティブログインシェルを開始しました。 bash-lオプションは、ログインシェルとしてシェルを開始します。

次に、 nohup を使用して、バックグラウンドで sleepinfinityというプロセスを開始しました。 標準出力と標準エラーをファイルnohup.outにリダイレクトしました。

最後に、exitコマンドを使用してインタラクティブログインシェルを終了しました。

2.1. プロセス開始時にPIDを保存する

上記のnohupを使用してプロセスを開始したとき、コマンド実行の出力は [1]20634でした。 括弧内の数字1は、ジョブIDです。 ジョブIDの後の番号20634は、 sleepinfinityコマンドを実行することによって生成されたプロセスのPIDです。

このPIDを後で使用して、プロセスをチェックまたは制御できます。 たとえば、プロセスがまだ実行されているかどうかを確認できます。

$ ps -ef -o pid | grep 20634
20634

プロセスのPIDを覚えておくために手動で書き留める代わりに、PIDをファイルに保存して、後で使用することができます。

$ bash -l
$ nohup sleep infinity >& nohup.out &
[1] 21443
$ echo $! > $HOME/pid.nohup
$ exit
logout
$ cat $HOME/pid.nohup
21443

これで、PIDがファイル $ HOME /pid.nohupに保存されました。 $!は、バックグラウンドで実行された最後のコマンドのPIDです。この場合は sleepinfinityです。

したがって、後でこのPIDを使用して、たとえばプロセスを強制終了できます。

$ kill -9 `cat $HOME/pid.nohup`
[1]+  Killed                  nohup sleep infinity

2.2. psコマンドの使用

nohup で開始するときにプロセスのPIDをメモするのを忘れた場合は、後でpsを使用して取得できます。 既存のプロセスでコマンドsleepinfinityを検索してみましょう。

$ ps -ef | grep "sleep infinity"
alice     21443       1  0  00:27 pts/0    00:00:00 sleep infinity
alice     21673    4672  0  00:27 pts/0    00:00:00 grep sleep infinity

ここでは、grepを使用してpsの出力をフィルタリングしました。 ps コマンドの出力に表示されないため、検索では「nohup」という用語を使用しませんでした。

パイプ内のgrep“ sleep infinity” コマンドも出力にリストされているため、grepを使用してさらにフィルター処理できます。

$ ps -ef | grep "sleep infinity" | grep -v grep
alice     21443       1  0  00:27 pts/0    00:00:00 sleep infinity

最後に、 awk コマンドを使用して、プロセスのPIDのみを出力できます。

$ ps -ef | grep "sleep infinity" | grep -v grep | awk '{print $2}'
21443

2.3. pgrepコマンドの使用

または、 nohup で開始した後、プロセスのPIDをメモするのを忘れた場合は、pgrepコマンドを使用することもできます。

$ pgrep -a sleep
21443 sleep infinity

ここで、pgrep-aオプションは、コマンドをそのPIDと一緒に出力します。

3. shoptコマンドのhuponexitオプション

インタラクティブログインシェルのバックグラウンドでプロセスをもう一度生成してログアウトしましょう。 ただし、この場合、nohupなしでプロセスを開始します。

$ bash -l
$ sleep infinity &
[1] 25101
$ exit
logout
$

プロセスがまだ実行されているかどうかを確認しましょう。

$ ps -ef -o pid | grep 25101
25101

インタラクティブログインシェルからログアウトしても、プロセスはまだ実行されているようです。 つまり、ログアウト後もバックグラウンドプロセスを実行し続ける場合は、 nohup を使用する必要がないということですか?

答えは、移植性が必要な場合はnohupを使用する必要があるということです。 nohup を使用せずにバックグラウンドでコマンドを実行するだけでは、常に機能するとは限りません。

実際、この問題はシェルオプションhuponexitに関連しています。 このオプションの値は、shoptコマンドで確認できます。

$ shopt | grep huponexit
huponexit       off

shopt コマンドは、いくつかのシェルオプションを設定および表示するために使用されます。 huponexitオプションがオフの場合、Bashは、インタラクティブログインシェルが終了したときに、そのセッションで生成されたすでに実行中のプロセスにSIGHUPシグナルを送信しません。 そのため、 sleep infinity コマンドを実行して生成したプロセスは、exitコマンドでログインシェルを終了した後もまだ生きていました。

huponexitオプションを有効または無効にすることができます。 -s オプションを使用して有効にし、-uオプションを使用して無効にすることができます。

$ shopt -s huponexit
$ shopt | grep huponexit
huponexit       on
$ shopt -u huponexit
huponexit       off

それでは、 huponexit オプションを有効にして、動作を確認しましょう。

$ bash -l
$ shopt –s huponexit
$ shopt | grep huponexit
huponexit       on
$ sleep infinity &
[1] 26238
$ exit
logout
$ ps –ef –o pid | grep 26238
$

これで、ログインシェルからログアウトした後、カーネルがログアウト中にシグナル SIGHUP をプロセスに送信するため、プロセスは稼働していません。 したがって、このシグナルを受信すると、プロセスは終了しました。

4. 結論

この記事では、nohupコマンドで実行されたプロセスのPIDを取得する方法について説明しました。

nohup を使用してコマンドを実行しているときに、PIDを書き留めることができます。 ただし、後でpsおよびpgrepコマンドを使用してPIDを取得することは可能です。

shoptコマンドのhuponexitオプションにも触れました。 このオプションの値がonの場合、カーネルはログアウト中にシグナルSIGHUPをシェルの実行中のプロセスに送信します。