既にたくさんの人が同じような記事を書いていましたが、自分メモ。
参考
結論
以下のようにnohup
コマンドを使い、かつ&
の指定によってシェルスクリプトをバックグラウンドで動かせば良い
$nohup ./batch.sh &
sshログウアウトするとなぜ止まるのか
sshログインしている状態でバックグランドでシェルスクリプトを実行すると、sshdのログインシェル(bash)の子プロセスとしてシェルスクリプトが実行されます。
# プロセスの親子関係を確認
$pstree
init─┬─agetty
├─atd
├─auditd───{auditd}
├─crond
├─dbus-daemon
├─dhclient
├─6*[mingetty]
├─ntpd
├─rngd
├─rpc.statd
├─rpcbind
├─rsyslogd───3*[{rsyslogd}]
├─2*[sendmail]
├─sshd───sshd───sshd───bash───pstree
# バックグラウンドで./batchを実行
$./batch.sh &
# batch.shはsshdの子プロセスのbashプロセスの子プロセスとして実行されている
$pstree
init─┬─agetty
├─atd
├─auditd───{auditd}
├─crond
├─dbus-daemon
├─dhclient
├─6*[mingetty]
├─ntpd
├─rngd
├─rpc.statd
├─rpcbind
├─rsyslogd───3*[{rsyslogd}]
├─2*[sendmail]
├─sshd───sshd───sshd───bash─┬─batch.sh───sleep
│ └─pstree
└─udevd───2*[udevd]
上記の場合に、sshのログアウトを行うとbatch.shにハングアップシグナル(HUP)を送信し、そのタイミングでシェルスクリプトが終了してしまうからです。
nohupコマンドとは
nohup
コマンドを使うことで上記のようにHUPシグナルがシェルスクリプトなどに送信された時でも無視するようにすることができます。
これによってsshログアウト後もシェルスクリプトの継続が可能です。
なお、nohupコマンドで実行されたスクリプトの標準出力及び標準エラー出力はプログラムを実行しているディレクトリにnohup.out
というファイル名で保存されます。ディレクトリに書き込み権限がなければ$HOME/nohup.out
として保存されます。
スクリプトで大量の標準出力、標準エラー出力がされる場合にはファイルが肥大化するので必要ないものは捨てるなり対処が必要です。
そもそもシグナルとは
以下を参考にさせていただきました。
実行中のプロセスに対して、様々なイベントを通知するために利用されるもの。
例えばあるプロセスを止めたい場合にkill -KILL [ps number]
という感じでコマンドを使うことがあると思いますが、これも対象のプロセスにシグナル名KILL(9)を送信してプロセスを終了しています。
同じようにCtrl+Zよってプロセスを中断したり、Ctrl+Cによって終了したりすることもありますが、プロセスに該当するシグナルを送信して機能を実現しています。
今回のHUP(シグナル番号1)もシグナルの一つとして存在し、sshログアウトタイミングでHUPシグナルがシェルスクプトに送信されますが、nohupコマンドを使っていればHUPシグナルを受け取っても無視する挙動にすることができ、処理を継続することができていました。