shell終了後にバックグラウンドプロセスが閉じる理由
http://doc.okbase.net/leehomjan/archive/107550.html
linuxでテストを行うと、バックグラウンドプロセスが開始された後、exitを使用してログインshellを終了すると、shellが終了してもバックグラウンドプロセスは正常に動作しますが、ログインしたウィンドウを直接閉じる(xshellを直接閉じるなど)と、バックグラウンドプロセスは一緒に終了します.すべてログインを終了するのはなぜ前者のバックグラウンドプロセスが終了し、後者は終了しないのですか?
bashのmanualを表示すると、次の説明があります.
The shell exits by default upon receipt of a SIGHUP. Before exiting, an interactive shell resends the SIGHUP to all jobs, running or stopped. Stopped jobs are sent SIGCONT to ensure that they receive the SIGHUP.
これにより、バックグラウンドプロセスの終了は、shellにログインしてSIGHUP信号を受信した後、終了前にSIGHUPをすべてのジョブ(jobs)に転送するためであることが分かる.ジョブはSIGHUP受信により運転を終了する.
では、設定によって、ウィンドウが異常に閉じたときにバックグラウンドプロセスを継続して実行できますか?
答えは肯定的で、一般的に以下の4つの方法があります.
1.nohupを使用してコマンドを実行する
再ログイン後もフロントプロセスとバックグラウンドプロセスは実行されていますが、親プロセスはinitになります.
nohupは現在のディレクトリの下でnohup.outファイルを生成し、実際のコマンドの標準出力と標準エラーをnohup.outにリダイレクトします.
2.setsidでコマンドを実行する
setsidを使用すると、現在ログインしているshellのjobsでback.shとfore.shが見つからないことがわかります.また、終了前にback.shとfore.shの親プロセスがinitであるため、再ログイン後にback.shとfore.shに変更はありません.
3.disownコマンドの使用
再登録後もfore.shが終了していることが判明し、SIGHUP信号が受信されたことが判明した.このことからdisownはバックグラウンドプロセスにのみ機能することが分かる.
4. Catch SIGHUP信号
shellスクリプトの場合は、スクリプトに次の文を追加すればいいです.
Cプログラムであればsignal関数を使ってSIGHUPをブロックすればよい.
X.もちろん反対に、shellをexit終了時にSIGHUPをすべてのjobsに送信することもできます.具体的には以下のように設定します.
テキストリンク:http://leehomjan.iteye.com/blog/2146739
linuxでテストを行うと、バックグラウンドプロセスが開始された後、exitを使用してログインshellを終了すると、shellが終了してもバックグラウンドプロセスは正常に動作しますが、ログインしたウィンドウを直接閉じる(xshellを直接閉じるなど)と、バックグラウンドプロセスは一緒に終了します.すべてログインを終了するのはなぜ前者のバックグラウンドプロセスが終了し、後者は終了しないのですか?
bashのmanualを表示すると、次の説明があります.
The shell exits by default upon receipt of a SIGHUP. Before exiting, an interactive shell resends the SIGHUP to all jobs, running or stopped. Stopped jobs are sent SIGCONT to ensure that they receive the SIGHUP.
これにより、バックグラウンドプロセスの終了は、shellにログインしてSIGHUP信号を受信した後、終了前にSIGHUPをすべてのジョブ(jobs)に転送するためであることが分かる.ジョブはSIGHUP受信により運転を終了する.
では、設定によって、ウィンドウが異常に閉じたときにバックグラウンドプロセスを継続して実行できますか?
答えは肯定的で、一般的に以下の4つの方法があります.
1.nohupを使用してコマンドを実行する
# nohup ./back.sh &
# nohup ./fore.sh
^Z
[2]+ Stopped nohup ./fore.sh
# jobs
[1]- Running nohup ./back.sh &
[2]+ Stopped nohup ./fore.sh
# ps -o pid,ppid,pgid,sid,cmd
PID PPID PGID SID CMD
4766 4716 4766 4716 /bin/bash ./back.sh
4769 4716 4769 4716 /bin/bash ./fore.sh
# fg
nohup ./fore.sh
### ###
# ps -eo pid,paid,pgid,sid,cmd |grep -E "back|fore"
4766 1 4766 4716 /bin/bash ./back.sh
4769 1 4769 4716 /bin/bash ./fore.sh
再ログイン後もフロントプロセスとバックグラウンドプロセスは実行されていますが、親プロセスはinitになります.
nohupは現在のディレクトリの下でnohup.outファイルを生成し、実際のコマンドの標準出力と標準エラーをnohup.outにリダイレクトします.
2.setsidでコマンドを実行する
# setsid ./back.sh &
# setsid ./fore.sh
# jobs
# ps -eo pid,ppid,pgid,sid,cmd |grep -E "back|fore"
4871 1 4871 4871 /bin/bash ./back.sh
4874 1 4874 4874 /bin/bash ./fore.sh
### ###
# ps -eo pid,ppid,pgid,sid,cmd |grep -E "back|fore"
4871 1 4871 4871 /bin/bash ./back.sh
4874 1 4874 4874 /bin/bash ./fore.sh
setsidを使用すると、現在ログインしているshellのjobsでback.shとfore.shが見つからないことがわかります.また、終了前にback.shとfore.shの親プロセスがinitであるため、再ログイン後にback.shとfore.shに変更はありません.
3.disownコマンドの使用
# ./fore.sh
^Z
[2]+ Stopped
# jobs
[1]- Running ./back.sh &
[2]+ Stopped ./fore.sh
# ps -eo pid,ppid,pgid,sid,cmd |grep -E "back|fore"
5395 5361 5395 5361 /bin/bash ./back.sh
5396 5361 5396 5361 /bin/bash ./fore.sh
# disown -h %2
# disown -a %1
# jobs
[2]+ Stopped ./fore.sh
# fg
./fore.sh
### ###
# ps -eo pid,ppid,pgid,sid,cmd |grep -E "back|fore"
5395 5361 5395 5361 /bin/bash ./back.sh
再登録後もfore.shが終了していることが判明し、SIGHUP信号が受信されたことが判明した.このことからdisownはバックグラウンドプロセスにのみ機能することが分かる.
4. Catch SIGHUP信号
shellスクリプトの場合は、スクリプトに次の文を追加すればいいです.
# trap "" HUP
Cプログラムであればsignal関数を使ってSIGHUPをブロックすればよい.
signal(SIGHUP, SIG_IGN);
X.もちろん反対に、shellをexit終了時にSIGHUPをすべてのjobsに送信することもできます.具体的には以下のように設定します.
# shopt -s huponexit
テキストリンク:http://leehomjan.iteye.com/blog/2146739