Ich glaube nicht, dass Sie das umgehen können.
Mit -tt
, sshd
erzeugt einen Pseudo-Terminal und macht den Slave - Teil der stdin, stdout und Stderr der Schale, die den Fernbefehl ausführt.
sshd
liest, was von seinem (einzelnen) fd zum Master-Teil des Pseudo-Terminals kommt, und sendet dies (über einen einzelnen Kanal) an den ssh
Client. Es gibt keinen zweiten Kanal für stderr wie ohne -t
.
Beachten Sie außerdem, dass die Terminalleitungsdisziplin des Pseudo-Terminals die Ausgabe ändern kann (und dies standardmäßig tun wird). Beispielsweise wird der LF dort und nicht auf dem lokalen Terminal in CRLF konvertiert, sodass Sie möglicherweise die Ausgabe-Nachbearbeitung deaktivieren möchten.
$ 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
Auf der Eingabeseite werden viel mehr Dinge passieren (wie das ^C
Zeichen, das ein SIGINT verursacht, aber auch andere Signale, das Echo und die gesamte Handhabung im Zeileneditor des kanonischen Modus ).
Sie könnten stderr möglicherweise zu einem fifo umleiten und es mit einer Sekunde abrufen ssh
:
ssh -tt host 'mkfifo fifo && cmd 2> fifo' &
ssh host 'cat fifo' >&2
Aber die beste IMO wäre es, die Verwendung -t
insgesamt zu vermeiden . Das ist eigentlich nur für die interaktive Nutzung von einem echten Terminal aus gedacht.
Anstatt sich auf die Übertragung eines ^ C zu verlassen, damit die Verbindung geschlossen wird, können Sie einen Wrapper verwenden, der poll()
die unterbrochene ssh
oder geschlossene Verbindung erkennt .
Vielleicht so etwas wie (vereinfacht, Sie möchten eine Fehlerprüfung hinzufügen):
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'
Das $p->mask(STDOUT, POLLIN)
Obige mag albern erscheinen, aber die Idee ist, auf ein Hang-Hup-Ereignis zu warten (bis das Leseende der Pipe auf stdout geschlossen ist). POLLHUP als angeforderte Maske wird ignoriert. POLLHUP ist nur als zurückgegebenes Ereignis von Bedeutung (um anzuzeigen, dass das Schreibende geschlossen wurde).
Wir müssen einen Wert ungleich Null für die Ereignismaske angeben. Wenn wir verwenden 0
, perl
ruft nicht einmal an poll
. Hier verwenden wir also POLLIN.
Unabhängig von Ihrer Anforderung gibt poll () POLLERR zurück, wenn die Pipe unterbrochen wird.
Unter Solaris und FreeBSD, wo Pipes bidirektional sind, wird das Leseende der Pipe (das dort auch ein Schreibende ist) mit POLLHUP zurückgegeben (und POLLIN unter FreeBSD, wo Sie POLLIN anfordern müssen oder $p->poll()
nicht Rückkehr).
Ich kann nicht sagen, wie portabel es sonst außerhalb dieser drei Betriebssysteme ist.
parallel --tag -j1 'ssh -tt localhost perl/catch_wrap perl/catch_all_signals & sleep 1; killall -{} ssh' ::: {1..31}
, aber entfernen Sie das '-tt' und dann funktioniert es nicht.