Je ne pense pas que vous puissiez contourner cela.
Avec -tt
, sshd
engendre un pseudo-terminal et fait de la partie esclave les stdin, stdout et stderr du shell qui exécute la commande à distance.
sshd
lit ce qui vient de son (unique) fd vers la partie maître du pseudo-terminal et l'envoie (via un seul canal) au ssh
client. Il n'y a pas de deuxième canal pour stderr comme il n'y en a pas -t
.
De plus, notez que la discipline de ligne terminale du pseudo-terminal peut (et modifiera par défaut) la sortie. Par exemple, le LF sera converti en CRLF là-bas et non sur le terminal local, vous pouvez donc désactiver le post-traitement de sortie.
$ 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
Beaucoup plus de choses se produiront du côté de l'entrée (comme le ^C
caractère qui provoquera un SIGINT, mais aussi d'autres signaux, l'écho et toute la gestion impliquée dans l' éditeur de ligne en mode canonique ).
Vous pouvez éventuellement rediriger stderr vers un fifo et le récupérer en utilisant une seconde ssh
:
ssh -tt host 'mkfifo fifo && cmd 2> fifo' &
ssh host 'cat fifo' >&2
Mais le meilleur IMO serait d'éviter d'utiliser -t
complètement. Cela n'est vraiment destiné qu'à une utilisation interactive à partir d'un vrai terminal.
Au lieu de compter sur la transmission d'un ^ C pour laisser l'extrémité distante la connexion est fermée, vous pouvez utiliser un wrapper qui fait un poll()
pour détecter la ssh
connexion interrompue ou fermée.
Peut-être quelque chose comme (simplifié, vous voudrez ajouter une vérification d'erreur):
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'
Ce qui $p->mask(STDOUT, POLLIN)
précède peut sembler idiot, mais l'idée est d'attendre un événement de blocage (pour que l'extrémité de lecture du tuyau sur stdout soit fermée). POLLHUP en tant que masque demandé est ignoré. POLLHUP n'a de sens que comme un événement retourné (pour indiquer que la fin de l' écriture a été fermée).
Nous devons donner une valeur non nulle pour le masque d'événement. Si nous utilisons 0
, perl
n'appelle même pas poll
. Nous utilisons donc ici POLLIN.
Sous Linux, quoi que vous demandiez, si le canal est cassé, poll () renvoie POLLERR.
Sur Solaris et FreeBSD, où les tuyaux sont bi - directionnel, lorsque la fin de la lecture de la conduite (qui est aussi une extrémité d'écriture là - bas) est fermé, il revient avec POLLHUP (et POLLIN sur FreeBSD, où vous devez demander POLLIN ou bien $p->poll()
ne pas revenir).
Je ne peux pas dire à quel point il est portable en dehors de ces trois systèmes d'exploitation.
parallel --tag -j1 'ssh -tt localhost perl/catch_wrap perl/catch_all_signals & sleep 1; killall -{} ssh' ::: {1..31}
:, mais supprimez le '-tt' et cela ne fonctionnera pas.