SSHがバックグラウンドプロセスを待たないのはなぜですか?

SSHがバックグラウンドプロセスを待たないのはなぜですか?

ssh -tバックグラウンドジョブが完了するのを待つとどうなりますか?

例:

ssh user@example 'sleep 2 &'

sshが2秒後に返されるため、これは期待どおりに機能します。

ssh user@example -t 'sleep 2 &'

完了を待たずにsleepすぐに返します。

誰でもこれの理由を説明できますか?ssh -t返す前にすべてのバックグラウンドプロセスを完了する方法はありますか?

私のユースケースは、次のようにスクリプトを起動し、そのスクリプトが基本スクリプトがssh -t完了した後もアクティブなままにする必要があるいくつかのバックグラウンドタスクを開始することです。これまではこれはssh -t不可能でした。

答え1

それ以外の場合は、-t2つのパイプを介してsshdリモートシェルのstdout(およびサブシェル)とstderrを取得しますsleep(別のパイプを介してクライアントからの入力も送信します)。

sshdユーザーのログインシェルを開始したプロセスを待ちますが、そのプロセスが終了した後、stdoutパイプ(少なくともstderrパイプではなくopensshの場合)でeofを待ちます。

eofは、パイプの書き込み側プロセスに対して開いているファイル記述子がない場合に発生します。これは通常、stdoutが他にリダイレクトされていないすべてのプロセスが消えた場合にのみ発生します。

を使用すると、-tパイプsshdは使用されません。代わりに、リモートシェルとその子孫(stdin、stdout、stderr)とのすべての対話は、一対の擬似端末を使用して行われます。

擬似端末ペアの場合、sshdマスターと対話するための同様のeof処理はありませんが、少なくとも一部のシステムは、疑似端末のスレーブ側にまだ開いているプロセスがあるかどうかを知るための代替方法を提供します(下記の@JdeBP注釈を参照)。 )、sshd使用しないので、リモートユーザーのログインシェルを実行するプロセスが終了するのを待ってから終了します。

終了すると、ptyペアのマスター側が閉じます。これはptyが破壊されることを意味するので、スレーブ制御プロセスはSIGHUP(デフォルトで終了)を受け取ります。

編集する:最終結果は同じですが、最後の部分が正しくありません。バラより@UNIX.rootの答え正確に何が起こったのかを正確に説明してください。

答え2

(より多くの情報を含めるためにコメントをここに移動しました。)

許可された回答の一部SIGHUPが正しくありません。

終了すると、ptyペアのマスター側が閉じます。これはptyが破壊されることを意味するので、スレーブが制御するプロセスはSIGHUPを受信します。

そうではありません。 POSIXによると、「制御端末の端末インターフェースがモデムの切断を検出したときにSIGHUP信号を送信する必要があります。[...]プロセスを制御するの場合、ssh -t 'sleep 2 &'ttyの接続が切断され、すでにSIGHUP終了しているために制御プロセスに送信できないのは、終了する制御プロセスです。実際にsleep殺されたSIGHUP理由はいつでしたか?セッションリーダーの終了「このSIGHUP信号はすべてのプロセスに送信する必要があります。フォアグラウンドプロセスグループで」。

混乱した部分はそうですsleep 2 &。これはバックグラウンドで実行されるコマンドですが、そうではありません。バックグラウンドプロセスグループ。バックグラウンドプロセスグループ関連職業管理デフォルトでは、非対話型シェル(例ssh ... 'sleep 2 &':)では無効になっています。実際にsleep 2 &走っているフォアグラウンドプロセスグループ。たとえば、

$ ssh -t localhost 'sleep 2 & ps jt'
  PPID    PID   PGID    SID TTY       TPGID STAT   UID   TIME COMMAND
 88819  88825  88825  88825 pts/36    88825 Ss+      0   0:00 bash -c sleep 2 & ps jt
 88825  88826  88825  88825 pts/36    88825 S+       0   0:00 sleep 2
 88825  88827  88825  88825 pts/36    88825 R+       0   0:00 ps jt

ご覧のとおり、すべてのプロセスのPGID(88825)はbashシェルのPIDと同じで、TPGIDも88825です。つまり、バックグラウンドプロセスsleep 2 &もここにあります。フォアグラウンドプロセスグループ

比較については、以下を参照してください。

$ pgrep -af sleep
$ ssh -t localhost 'set -m; sleep 123 & ps jt'
  PPID    PID   PGID   SID TTY   TPGID STAT UID TIME COMMAND
 89002  89008  89008 89008 pts/3 89010 Ss     0 0:00 bash -c set -m; sleep 123 & ps jt
 89008  89009  89009 89008 pts/3 89010 S      0 0:00 sleep 123
 89008  89010  89010 89008 pts/3 89010 R+     0 0:00 ps jt
Connection to localhost closed.
$ ps j 89009
  PPID    PID   PGID    SID TTY       TPGID STAT   UID   TIME COMMAND
     1  89009  89009  89008 ?            -1 S        0   0:00 sleep 123
$

set -mジョブ制御が有効になっていると(sleep 2 &独自のプロセスグループ(PGID 89009)で実行されていることがわかります。バックグラウンドプロセスグループ。そして、ssh終了後もsleep実行を続けています。


(詳細については、次のようなシナリオを参照してください。+ "ssh -f"が機能しないと予想されます。)

答え3

使用wait:

ssh user@example -t 'sleep 2 & wait'

関連情報