ssh -tによるstderr

ssh -tによるstderr

これにより、出力はSTDERRに送信されますが、Ctrl+は伝播されませんC(つまり、Ctrl+はC終了しますがsshリモートは終了しませんsleep)。

$ ssh localhost 'sleep 100;echo foo ">&2"'

これはCtrl+を伝播しますC(つまり、Ctrl+はリモートCを終了します)、STDERRをSTDOUTに送信します。sshsleep

$ ssh -tt localhost 'sleep 100;echo foo ">&2"'

Ctrl+を伝播し続けながら、2番目の出力にSTDERR出力をSTDERRに送信させるにはどうすればよいですかC

背景

CtrlGNU Parallelは「ssh -tt」を使用して+を伝播しますC。これにより、リモートで実行されているジョブを終了できます。ただし、STDERRに送信されたデータは受信側からSTDERRに移動する必要があります。

答え1

私はあなたがこの問題を解決できないと思います。

-tt擬似端末を作成しsshd、スレーブ部分をリモートコマンドを実行するシェルのstdin、stdout、およびstderrにするために使用されます。

sshd(シングル)fdの内容を擬似端末の主要部分に読み込み(シングルチャンネル経由)クライアントに送信しますssh。がないため、stderrの2番目のチャンネルはありません-t

また、擬似端末の端末回線規則は出力を変更でき、デフォルトで変更されます。たとえば、LF はローカル端末ではなくそこから CRLF に変換されるため、出力後処理をディセーブルにする必要があります。

$ ssh  localhost 'echo x' | hd
00000000  78 0a                                             |x.|
00000002
$ ssh -t localhost 'echo x' | hd
00000000  78 0d 0a                                          |x..|
00000003
$ ssh -t localhost 'stty -opost; echo x' | hd
00000000  78 0a                                             |x.|
00000002

入力側ではるかに多くのことが起こります(例えば、^CSIGINTを発生させる文字だけでなく、他の信号、エコー、および関連するすべての処理も含む)。正式モードラインエディタ)。

stderrをfifoにリダイレクトし、2番目のものを使用して検索できますssh

ssh -tt host 'mkfifo fifo && cmd 2> fifo' &
ssh host 'cat fifo' >&2

しかし、私の考えには、最善の方法は-tそれを完全に避けることです。これは、実際の端末で対話式に使用する場合にのみ適しています。

poll()リモート側で接続を閉じるために送信に依存する代わりに、終了または閉じた接続を検出するためにトグルを実行するラッパーを使用できますssh

おそらく次のようになります(単純化した場合は、いくつかのエラーチェックを追加する必要があります)。

LC_HUP_DETECTOR='
  use IO::Poll;
  $SIG{CHLD} = sub {$done = 1};
  $p = IO::Poll->new;
  $p->mask(STDOUT, POLLIN);
  $pid=fork; unless($pid) {setpgrp; exec @ARGV; die "exec: $!\n"}
  $p->poll;
  kill SIGHUP, -$pid unless $done;
  wait; exit ($?&127 ? 128+($?&127) : 1+$?>>8)
' ssh host 'perl -e "$LC_HUP_DETECTOR" some cmd'

上記は$p->mask(STDOUT, POLLIN)愚かに見えるかもしれませんが、保留中のイベント(stdoutでパイプの読み取りの終わりが閉じるまで)を待つのがアイデアです。 POLLHUPによる必須マスクは無視されます。 POLLHUP は戻りイベントとしてのみ意味があります。書く端は閉じています)。

イベントマスクにゼロ以外の値を指定する必要があります。使用すると0呼び出されperlませんpoll。だからここではPOLLINを使用します。

Linuxでは、要求された内容に関係なくパイプが壊れると、poll()はPOLLERRを返します。

SolarisとFreeBSDでは、パイプは双方向であり、パイプの読み取り終了(書き込み終了)も閉じるとPOLLHUPに返されます。 FreeBSD では POLLIN を要求する必要があり、それ以外の場合は$p->poll()返されません。 )返品)。

これら3つのオペレーティングシステムの外でどれほど移植性に優れているかは言えません。

答え2

他のプラットフォームでも動作させるための最終ソリューションとなりました。 SSHクライアントの接続が失われたことを確認して、親プロセスのpidが1になります。

$SIG{CHLD} = sub { $done = 1; };
$pid = fork;
unless($pid) {
    # Make own process group to be able to kill HUP it later
    setpgrp;
    exec $ENV{SHELL}, "-c", ($bashfunc."@ARGV");
    die "exec: $!\n";
}
do {
    # Parent is not init (ppid=1), so sshd is alive
    # Exponential sleep up to 1 sec
    $s = $s < 1 ? 0.001 + $s * 1.03 : $s;
    select(undef, undef, undef, $s);
} until ($done || getppid == 1);
# Kill HUP the process group if job not done
kill(SIGHUP, -${pid}) unless $done;
wait;
exit ($?&127 ? 128+($?&127) : 1+$?>>8)

関連情報