Non penso che tu possa aggirare quello.
Con -tt
, sshd
genera uno pseudo-terminale e rende la parte slave lo stdin, lo stdout e lo stderr della shell che esegue il comando remoto.
sshd
legge ciò che viene dal suo (singolo) fd alla parte master dello pseudo-terminale e lo invia (tramite un singolo canale) al ssh
client. 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 ^C
personaggio 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 -t
tutto. 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 ssh
connessione 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
, perl
non 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.