回答:
bashドキュメントの引用(from man bash
):
JOB CONTROL
Job control refers to the ability to selectively stop
(suspend) the execution of processes and continue (resume)
their execution at a later point. A user typically employs
this facility via an interactive interface supplied jointly
by the operating system kernel's terminal driver and bash.
したがって、非常に簡単に言えば、set -m
(インタラクティブシェルのデフォルト)を使用するfg
とbg
、などのビルトインを使用でき、これらはset +m
(非インタラクティブシェルのデフォルト)では無効になります。
ただし、ジョブ制御と終了時のバックグラウンドプロセスの終了との関係は明らかではありませんが、1つあることを確認できます:set -m; (sleep 10 ; touch control-on) &
コマンドを入力した直後にシェルを終了した場合、実行するとファイルが作成されますが、実行set +m; (sleep 10 ; touch control-off) &
されません。
答えは、ドキュメントの残りの部分にあると思いますset -m
:
-m Monitor mode. [...] Background pro‐
cesses run in a separate process group and a line con‐
taining their exit status is printed upon their comple‐
tion.
これは、下で開始されたバックグラウンドジョブset +m
は実際の「バックグラウンドプロセス」ではないことを意味します(「バックグラウンドプロセスはプロセスグループIDが端末のものと異なる」)。適切なバックグラウンドプロセスのようなプロセスグループ。これは、動作はそのバックグラウンドジョブのいくつかの前にするとき、シェルが終了しますを観察説明:私が正しく理解していれば終了するとき、信号は(これで起動バックグラウンドジョブを殺すシェルと同じプロセスグループ内のプロセスに送信されますset +m
)ではなく、他のプロセスグループのものに(したがって、真のバックグラウンドプロセスはそのままで開始されますset -m
)。
したがって、あなたの場合、startup.sh
スクリプトはおそらくバックグラウンドジョブを開始します。リンクした質問のようにSSH経由などでこのスクリプトを非対話的に実行すると、ジョブ制御が無効になり、「バックグラウンド」ジョブはリモートシェルのプロセスグループを共有するため、シェルが終了するとすぐに強制終了されます。逆に、そのシェルでジョブ制御を有効にすると、バックグラウンドジョブは独自のプロセスグループを取得し、その親シェルが終了しても削除されません。
これはgithubの問題リストで見つけましたが、これはあなたの質問に本当に答えていると思います。
これは実際にはSSHの問題ではなく、BASHの非インタラクティブ/インタラクティブモードに関する微妙な動作と、プロセスグループへの信号伝播です。
以下は/programming/14679178/why-does-ssh-wait-for-my-subshells-without-t-and-kill-them-with-t/14866774#14866774 とhttpに基づいてい ます: //www.itp.uzh.ch/~dpotter/howto/daemonize、いくつかの前提条件は完全に検証されていませんが、これがどのように機能するかについてのテストは確認されているようです。
pty / tty = false
起動されたbashシェルは、開始されたプロセスのstdout / stderr / stdinに接続し、ソケットに何も接続されず、その子が終了するまで実行され続けます。優れたデーモンプロセスは、子プロセスが終了するのを待たずに、子プロセスをフォークしてから終了します。このモードでは、SIGHUPはSSHによって子プロセスに送信されません。これは、自身のデーモン化を処理し、バックグラウンドにする必要のないプロセスを実行するほとんどのスクリプトで正常に機能すると考えています。initスクリプトがプロセスをバックグラウンドするために「&」を使用する場合、主な問題は、セッションが終了した場合にSIGHUPをトリガーするため、バックグラウンドプロセスがstdinからの読み取りを試みるかどうかである可能性があります。
pty / tty = true *
プロセスが開始initスクリプトの背景場合は、親BASHシェルが終了するターン表情で、終了した子プロセスに待機していないだろう、直ちに以来とstdoutでブロックされていない、SSH接続に終了コードを返します。 / stderr / stdin。これにより、SIGHUPが親bashシェルプロセスグループに送信され、bashの非対話モードではジョブ制御が無効になっているため、起動されたばかりの子プロセスが含まれます。デーモンプロセスがフォークまたはフォークされたプロセスで明示的に新しいプロセスセッションを開始する場合、その子プロセスまたはその子プロセスは、終了するBASH親プロセスからSIGHUPを受け取りません。これは、SIGTERMが表示される一時停止ジョブとは異なることに注意してください。この問題は、わずかな競合状態に関係している場合があります。 http://www.itp.uzh.ch/~dpotter/howto/daemonizeを見ると、親セッションが終了する前に実行されない可能性があるフォークされたプロセスによって、新しいセッションが作成されていることがわかります。上記の成功/失敗の動作。スリープ文は、分岐したプロセスが新しいセッションを作成するのに十分な時間を許可します。これが場合によっては機能する理由です。
pty / tty = trueであり、bashでジョブ制御が明示的に有効になっています
SSHは、bashシェルまたは起動された子プロセスのstdout / stderr / stdinに接続しません。つまり、親bashシェルが要求されたコマンドの実行を開始するとすぐに終了します。この場合、ジョブ制御が明示的に有効になっていると、bashシェルによって起動され、それらをバックグラウンドにする '&'を持つプロセスはすぐに別のセッションに配置され、BASHセッションへの親プロセスが終了するときにSIGHUPシグナルを受信しません(この場合のSSH接続)。
修正に必要なもの
バックグラウンドのプロセス/サービスを操作する場合、特別なケースとしてrun / sudo操作のドキュメントでソリューションを明示的に言及するだけでよいと思います。基本的に「pty = false」を使用するか、それが不可能な場合は、最初のコマンドとしてジョブ制御を明示的に有効にすると、動作が正しくなります。
tomcat/bin/startup.sh
にfg
/に関連していbg
ますか?