あなたはそれを回避することはできないと思います。
スポーン擬似端末とスレーブ部にリモートコマンドを実行するシェルのSTDIN、stdoutとstderrを行います。-tt
sshd
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
入力側ではさらに多くのことが起こります(^C
SIGINTを引き起こす文字だけでなく、その他の信号、エコー、および正規モードの行エディターに関連するすべての処理)。
stderrをfifoにリダイレクトし、2番目を使用して取得することができますssh
。
ssh -tt host 'mkfifo fifo && cmd 2> fifo' &
ssh host 'cat fifo' >&2
しかし、最高のIMOは、-t
まったく使用しないことです。これは実際には、実際の端末からのインタラクティブな使用のみを目的としています。
^ Cの送信に依存してリモートエンドで接続が閉じられるようにする代わりに、を行うラッパーを使用して、強制終了または閉じられた接続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)
上記の愚かに見えるかもしれませんが、考え方は(閉じられるように標準出力にパイプの読取終了のための)ハングHUPイベントを待つことです。要求されたマスクとしてのPOLLHUP は無視されます。POLLHUPは、返されたイベントとしてのみ意味があります(書き込みの終わりが閉じられたことを通知するため)。
イベントマスクにはゼロ以外の値を指定する必要があります。を使用する場合0
、perl
呼び出しさえしませんpoll
。したがって、ここではPOLLINを使用します。
Linuxでは、要求が何であれ、パイプが壊れた場合、poll()はPOLLERRを返します。
パイプの読み取り終了(も書き終わりですが)閉じているパイプは双方向でのSolarisとFreeBSD、、で、それはあなたがPOLLINを要求する必要がFreeBSD上でPOLLHUP(とPOLLIN、と返すか、他に$p->poll()
ありません戻る)。
それ以外の点では、これら3つのオペレーティングシステムの外では、どれほどポータブルであるかはわかりません。
parallel --tag -j1 'ssh -tt localhost perl/catch_wrap perl/catch_all_signals & sleep 1; killall -{} ssh' ::: {1..31}
が、「-tt」を削除すると機能しなくなります。