SSH 接続で時間の掛かるシェルスクリプトをバックグラウンドで走らせて帰りたいのに、SSH 接続を切るとジョブが死んでしまいます。SSH 接続に限らず目の前の OS からログアウトしたりターミナル エミュレータを終了しても同じ現象が起こります。
この症状は正常です。なぜなら、バックグラウンド ジョブを起動したプロセス(ログイン シェル)が子プロセスである該当のバックグラウンドジョブをハングアップ シグナル( HUP )によって終了させるからです。
シェルスクリプトを起動した親プロセスは子プロセスの終了状態を監視しています。ですからログアウトして親プロセスであるシェルが終了すると子プロセスはゾンビ プロセスとなってしまうので親プロセスとなるシェル(ログインシェル)は子プロセスであるバックグラウンド ジョブを kill ( kill -HUP ) するのです。
ジョブを kill されないようにするには nohup コマンドを使います。nohup コマンドは HUP シグナルを無視するようにプログラムを実行します。また標準出力、標準エラー出力はファイルになります。STDOUT, STDERR に出力データがなくてもファイルは作成されます。
nohup コマンドでバックグラウンドで走らせたいバッチ処理プログラムなどを実行すればログアウトしても kill されないのでプロセスは継続しますから心置きなく家へ帰れます。nohup コマンドは Linux 以外にも Unix 系の OS なら使えるでしょう。私は Mac OS X で確認しています。無ければ GNU の coreutils にあります。
$ nohup ./abc.sh &
abc.sh の標準出力、標準エラー出力に送られたデータはプログラムを実行したディレクトリに nohup.out というファイル名で保存される。プログラムを実行したディレクトリに書き込み権限が無ければ $HOME/nohup.out に保存される。
$ nohup ./abc.sh > out.log &
abc.sh の標準出力が out.log になる。標準エラー出力は nohup.out で保存先は例1と同様にプログラムを実行したディレクトリか $HOME になる。
$ nohup ./abc.sh > out.log 2> err.log &
abc.sh の標準出力が out.log になる。標準エラー出力は err.log です。
以上のようなコマンドを実行した後はログアウトして大丈夫です。心配なら再度ログインしてプロセスを確認してみましょう。
SSH でログインしている場合は3つの I/O ストリーム をリダイレクトしておきます。SSH 接続でバックグラウド ジョブを実行する場合、日常的に標準出力、標準エラー出力をリダイレクトしていると思いますがここで重要なのは標準入力を閉じておくことです。具体的には /dev/null にします。
$ nohup ./abc.sh > out.log 2> err.log < /dev/null &
詳しいことは SSH Frequently Asked Questions をご覧下さい。
もうひとつ、nohup は実行したプログラムを自動的にバックグラウンド ジョブにするものではありません。バックグラウンドで実行するなら & を付けて実行するか bg コマンドを使いましょう。
nohup で実行中のプログラムを終了させるにはプロセスIDを調べて kill コマンドで強制終了(kill -KILL)します。
最終更新日: 2014年05月03日(土) / カテゴリー: Unix, Linux