No creo que puedas evitar eso.
Con -tt
, sshd
genera un pseudo-terminal y hace que la parte esclava sea el stdin, stdout y stderr del shell que ejecuta el comando remoto.
sshd
lee lo que viene de su fd (único) a la parte maestra del pseudo-terminal y lo envía (a través de un solo canal) al ssh
cliente. No hay un segundo canal para stderr, ya que no existe -t
.
Además, tenga en cuenta que la disciplina de línea terminal del pseudo-terminal puede (y por defecto) alterará la salida. Por ejemplo, el LF se convertirá en CRLF allí y no en el terminal local, por lo que es posible que desee deshabilitar el procesamiento posterior de salida.
$ 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
Sucederán muchas más cosas en el lado de entrada (como el ^C
carácter que causará un SIGINT, pero también otras señales, el eco y todo el manejo involucrado en el editor de línea de modo canónico ).
Posiblemente podría redirigir stderr a un fifo y recuperarlo usando un segundo ssh
:
ssh -tt host 'mkfifo fifo && cmd 2> fifo' &
ssh host 'cat fifo' >&2
Pero la mejor OMI sería evitar el uso por -t
completo. Eso realmente solo está destinado al uso interactivo desde un terminal real.
En lugar de confiar en la transmisión de un ^ C para permitir que el control remoto finalice la conexión, puede usar un contenedor que haga un a poll()
para detectar la ssh
conexión desconectada o cerrada.
Tal vez algo como (simplificado, querrás agregar alguna comprobación de errores):
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'
Lo $p->mask(STDOUT, POLLIN)
anterior puede parecer una tontería, pero la idea es esperar un evento de hang-hup (para que se cierre el extremo de lectura de la tubería en stdout). POLLHUP como máscara solicitada se ignora. POLLHUP solo tiene sentido como un evento devuelto (para indicar que el final de la escritura se ha cerrado).
Tenemos que dar un valor distinto de cero para la máscara de eventos. Si usamos 0
, perl
ni siquiera llama poll
. Entonces aquí usamos POLLIN.
En Linux, cualquier cosa que solicite, si la tubería se rompe, poll () devuelve POLLERR.
En Solaris y FreeBSD, donde las tuberías son bidireccionales, cuando el extremo de lectura de la tubería (que también es un extremo de escritura allí) está cerrado, regresa con POLLHUP (y POLLIN en FreeBSD, donde tiene que solicitar POLLIN o $p->poll()
no lo hace). regreso).
No puedo decir qué tan portátil es fuera de esos tres sistemas operativos.
parallel --tag -j1 'ssh -tt localhost perl/catch_wrap perl/catch_all_signals & sleep 1; killall -{} ssh' ::: {1..31}
pero elimina el '-tt' y luego no funciona.