Non penso che tu possa aggirare quello.
Con -tt, sshdgenera uno pseudo-terminale e rende la parte slave lo stdin, lo stdout e lo stderr della shell che esegue il comando remoto.
sshdlegge ciò che viene dal suo (singolo) fd alla parte master dello pseudo-terminale e lo invia (tramite un singolo canale) al sshclient. Non esiste un secondo canale per stderr come è senza -t.
Inoltre si noti che la disciplina della linea terminale dello pseudo-terminale può (e per impostazione predefinita) alterare l'uscita. Ad esempio, l'LF verrà convertito in CRLF laggiù e non sul terminale locale, quindi potresti voler disabilitare la post-elaborazione dell'output.
$ 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
Accadranno molte più cose sul lato input (come il ^Cpersonaggio che causerà un SIGINT, ma anche altri segnali, l'eco e tutta la gestione coinvolta nell'editor di linea canonica ).
Potresti eventualmente reindirizzare stderr a un FIFO e recuperarlo usando un secondo ssh:
ssh -tt host 'mkfifo fifo && cmd 2> fifo' &
ssh host 'cat fifo' >&2
Ma la migliore IMO sarebbe quella di evitare di usarla del -ttutto. Questo è davvero pensato solo per l'uso interattivo da un vero terminale.
Invece di fare affidamento sulla trasmissione di un ^ C per consentire al terminale remoto di chiudere la connessione, è possibile utilizzare un wrapper che esegue un poll()rilevamento della sshconnessione interrotta o chiusa.
Forse qualcosa di simile (semplificato, ti consigliamo di aggiungere un po 'di controllo degli errori):
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'
Quanto $p->mask(STDOUT, POLLIN)sopra può sembrare sciocco, ma l'idea è di attendere un evento hang-hup (per chiudere la fine della lettura della pipe su stdout). POLLHUP come maschera richiesta viene ignorato. POLLHUP è significativo solo come evento restituito (per dire che la fine della scrittura è stata chiusa).
Dobbiamo fornire un valore diverso da zero per la maschera dell'evento. Se usiamo 0, perlnon chiamiamo nemmeno poll. Quindi qui usiamo POLLIN.
Su Linux, qualunque cosa tu richieda, se la pipe si rompe, poll () restituisce POLLERR.
Su Solaris e FreeBSD, dove le pipe sono bidirezionali, quando l'estremità di lettura della pipe (che è anche una fine di scrittura lì) è chiusa, ritorna con POLLHUP (e POLLIN su FreeBSD, dove è necessario richiedere POLLIN oppure $p->poll()no ritorno).
Non posso dire quanto sia portatile al di fuori di questi tre sistemi operativi.
parallel --tag -j1 'ssh -tt localhost perl/catch_wrap perl/catch_all_signals & sleep 1; killall -{} ssh' ::: {1..31}:, ma rimuovi '-tt' e quindi non funziona.