答え1
bashドキュメントの引用(から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) &
そのコマンドを入力した直後にシェルを終了すると、run を実行するとファイルが生成されますが、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とは異なるプロセスグループIDを持つプロセスです」)。その操作を開始したシェルと同じプロセスグループIDを共有します。独自のプロセスグループIDを持つ代わりに。プロセスグループは適切なバックグラウンドプロセスと同じです。これは、いくつかのバックグラウンド操作の前にシェルがシャットダウンしたときに観察される動作を説明します。正しく理解した場合は、シャットダウンすると、シェルと同じプロセスグループ内のプロセスにシグナルが送信されます(したがって、開始されたバックグラウンドジョブが終了しますset +m
)。他のプロセスグループのプロセス(したがって、以下で開始された実際のバックグラウンドプロセスは考慮されませんset -m
)
したがって、あなたの場合、スクリプトはバックグラウンドstartup.sh
ジョブを開始できます。このスクリプトが非対話型(たとえば、リンクされた質問のようにSSHを介して)で実行されると、ジョブ制御は無効になり、「バックグラウンド」ジョブはリモートシェルのプロセスグループを共有するため、シェルが終了すると終了します。代わりに、そのシェルでジョブ制御を有効にすると、バックグラウンドジョブは独自のプロセスグループを取得し、親シェルが終了すると終了しません。
答え2
私はgithubの問題リストでこれを見つけましたが、これはあなたの質問に答えたと思います。
これは実際にはSSHの問題ではありませんが、BASH非対話型/対話型モードとプロセスグループへの信号伝播を取り巻く微妙な動作に近いです。
以下は以下に基づいています。 https://stackoverflow.com/questions/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 = 偽
起動されたbashシェルは、起動されたプロセスのstdout / stderr / stdinに接続され、ソケットに何も接続されず、その子プロセスが終了するまで実行され続けます。良いデーモンは、子プロセスが終了するのを待たずに子プロセスを分岐してから終了することを確認します。このモードでは、SSH を介してサブプロセスに SIGHUP が送信されません。私はこれが独自の悪魔の除去を処理し、バックグラウンドで実行する必要がないプロセスを実行するほとんどのスクリプトでうまく機能すると思います。 initスクリプトが「&」を使用してプロセスをバックグラウンド化する場合、主な問題はバックグラウンドプロセスがstdinから読み取ろうとすることです。これは、セッションが終了したときにSIGHUPをトリガーするためです。
pty/tty = true*
initスクリプトがバックグラウンドでプロセスを開始すると、親BASHシェルはSSH接続に終了コードを返します。これは、子プロセスが終了するのを待たずにstdout / stderrでブロックされないため、すぐに終了します。 /stdin。これにより、SIGHUP が親 bash シェル・プロセス・グループに送信されます。これには、bashの非対話型モードでジョブ制御が無効になっているため、起動したばかりの子プロセスが含まれます。デーモンがフォークされたとき、またはフォークされたプロセス内で新しいプロセスセッションを明示的に開始した場合、そのデーモンまたはそのサブプロセスは既存のBASH親プロセスからSIGHUPを受け取りません。これは、SIGTERMが表示される一時停止ジョブとは異なります。私はこの問題が時々いくつかの競争条件に関連していると思います。悪魔化への標準的なアプローチを見てみましょう。 http://www.itp.uzh.ch/~dpotter/howto/daemonize、親プロセスが終了するまで実行されない可能性があるフォークされたプロセスによって新しいセッションが作成され、上記のランダム成功/失敗動作が発生するコードをコードに表示できます。 sleepステートメントは、分岐プロセスに新しいセッションを作成するのに十分な時間を提供するため、場合によっては機能します。
pty/tty = trueで、bashでジョブ制御を明示的に有効にします。
SSHはbashシェルまたは起動された子プロセスのstdout / stderr / stdinに接続しません。つまり、親bashシェルが要求されたコマンドの実行を開始すると終了します。この場合、ジョブ制御が明示的に有効になると、「&」を使用してbashシェルで開始されたすべてのプロセスはすぐに別々のセッションに入り、SIGHUP信号(この場合はSSH接続)を受信しません。
直すべきこと
これらのソリューションは、バックグラウンドプロセス/サービスを使用するときに特別なケースとして、run / sudo作業文書に明示的に言及する必要があると思います。デフォルトでは、「pty = false」を使用するか、これが不可能な場合は、最初のコマンドでジョブ制御を明示的に有効にすると動作が正しくなります。