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) &
の実行 そのコマンドを入力した直後にシェルを終了すると、ファイルが作成されますが、 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 とは異なるプロセスです」)。これは、シェルがそのバックグラウンド ジョブのいくつかの前に終了するときに観察される動作を説明しています:私が正しく理解している場合、終了すると、シェルと同じプロセス グループ内のプロセスにシグナルが送信されます (したがって、set +m
で開始されたバックグラウンド ジョブが強制終了されます)。 )、しかし他のプロセス グループのプロセスには適用されません (したがって、set -m
で開始された真のバックグラウンド プロセスはそのままにしておきます) ).
したがって、あなたの場合、 startup.sh
スクリプトはおそらくバックグラウンド ジョブを開始します。リンク先の質問のように SSH を介してこのスクリプトを非対話的に実行すると、ジョブ制御が無効になり、「バックグラウンド」ジョブがリモート シェルのプロセス グループを共有するため、そのシェルが終了するとすぐに強制終了されます。逆に、そのシェルでジョブ制御を有効にすると、バックグラウンド ジョブは独自のプロセス グループを取得し、その親シェルが終了しても強制終了されません。
これは github issue list で見つけました。これは本当にあなたの質問に答えていると思います。
<ブロック引用>これは実際には 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 =false
起動された bash シェルは、開始されたプロセスの stdout/stderr/stdin に接続し、ソケットに何も接続されず、その子プロセスが終了するまで実行を続けます。良いデーモン プロセスは、子プロセスが終了するのを待たずに、子プロセスを fork してから終了します。このモードでは、SSH によって子プロセスに SIGHUP が送信されません。これは、デーモン化自体を処理し、バックグラウンドで実行する必要がないプロセスを実行するほとんどのスクリプトで正しく機能すると思います。 init スクリプトが「&」を使用してプロセスをバックグラウンド化する場合、主な問題は、バックグラウンド化されたプロセスが stdin からの読み取りを試行するかどうかである可能性があります。これは、セッションが終了した場合に SIGHUP がトリガーされるためです。
pty/tty =true*
初期化スクリプトがプロセスの開始をバックグラウンド化する場合、親 BASHshell は SSH 接続に終了コードを返します。これは、子プロセスの終了を待機しておらず、stdout/stderr/ でブロックされていないため、すぐに終了するように見えます。標準入力。これにより、親の bash シェル プロセス グループに SIGHUP が送信されます。bash の非対話モードではジョブ制御が無効になっているため、起動したばかりの子プロセスが含まれます。フォーク時またはフォークされたプロセス内で、デーモン プロセスが新しいプロセス セッションを明示的に開始する場合、デーモン プロセスまたはその子プロセスは、終了する BASH 親プロセスから SIGHUP を受信しません。これは、SIGTERM が表示されるsuspendedjobs とは異なることに注意してください。この onlyworking に関する問題は、わずかな競合状態に関係していると思われます。 Deamonize の標準的なアプローチ (http://www.itp.uzh.ch/~dpotter/howto/daemonize) を見ると、コード内で新しいセッションが fork されたプロセスによって作成されていることがわかります。親が終了するため、上記のランダムな成功/失敗の動作が発生します。 sleep ステートメントは、フォークされたプロセスが新しいセッションを作成するのに十分な時間を与えるため、場合によっては機能します。
pty/tty =true で、ジョブ制御が bash で明示的に有効になっている
SSH は、bash シェルまたは起動された子プロセスの stdout/stderr/stdin に接続しません。つまり、親の bash シェルが要求されたコマンドの実行を終了するとすぐに終了します。この場合、ジョブ制御を明示的に有効にして、バックグラウンドに「&」を使用して bash シェルによって起動されたプロセスは、すぐに別のセッションに配置され、BASH セッションへの親プロセスが終了したときに SIGHUP シグナルを受信しません (この場合は SSH 接続)。
修正が必要なこと
バックグラウンド プロセス/サービスを使用する場合の特別なケースとして、run/sudo 操作のドキュメントにソリューションを明示的に記載する必要があると思います。基本的に「pty=false」を使用するか、それが不可能な場合は、最初のコマンドとして明示的にジョブ制御を有効にすると、動作が正しくなります。
https://github.com/fabric/fabric/issues/395 より