Nie sądzę, że można to obejść.
Za pomocą -tt
, sshd
spawnuje pseudo-terminal i sprawia, że slave staje się stdin, stdout i stderr powłoki wykonującej zdalne polecenie.
sshd
odczytuje to, co nadchodzi z (pojedynczego) fd do głównej części pseudo-terminala i wysyła to (jednym kanałem) do ssh
klienta. Nie ma drugiego kanału dla stderr, ponieważ jest bez -t
.
Ponadto zauważ, że dyscyplina linii pseudo-terminala może (i domyślnie) zmieni dane wyjściowe. Na przykład LF zostanie tam przekonwertowany na CRLF, a nie na lokalnym terminalu, więc możesz chcieć wyłączyć przetwarzanie końcowe.
$ 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
Po stronie wejściowej wydarzy się znacznie więcej rzeczy (np. ^C
Znak, który spowoduje SIGINT, ale także inne sygnały, echo i cała obsługa związana z edytorem linii w trybie kanonicznym ).
Możesz ewentualnie przekierować stderr do fifo i odzyskać go za pomocą sekundy ssh
:
ssh -tt host 'mkfifo fifo && cmd 2> fifo' &
ssh host 'cat fifo' >&2
Ale najlepszym IMO byłoby -t
całkowite uniknięcie używania . To naprawdę jest przeznaczone tylko do interaktywnego użytku z prawdziwego terminala.
Zamiast polegać na transmisji ^ C, aby umożliwić zdalnemu końcowi połączenie jest zamknięte, możesz użyć opakowania, które poll()
wykrywa przerwane ssh
lub zamknięte połączenie.
Może coś takiego (uproszczone, będziesz chciał dodać trochę sprawdzania błędów):
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'
$p->mask(STDOUT, POLLIN)
Powyżej może wydawać się głupie, ale chodzi o to, aby czekać na imprezie hang-hup (na koniec czytania rury na stdout być zamknięte). POLLHUP jako żądana maska jest ignorowana. POLLHUP ma znaczenie jedynie jako wydarzenie zwrócone (aby powiedzieć, że koniec pisania został zamknięty).
Musimy podać niezerową wartość dla maski zdarzenia. Jeśli skorzystamy 0
, perl
nawet nie zadzwonimy poll
. Więc tutaj używamy POLLIN.
W Linuksie, cokolwiek poprosisz, jeśli potok się zepsuje, poll () zwróci POLLERR.
W systemach Solaris i FreeBSD, gdzie potoki są dwukierunkowe, gdy koniec odczytu potoku (który jest tam również końcem zapisu) jest zamknięty, zwraca on z POLLHUP (i POLLIN na FreeBSD, gdzie musisz poprosić POLLIN, w przeciwnym $p->poll()
razie powrót).
Nie mogę powiedzieć, jak przenośny jest poza tymi trzema systemami operacyjnymi.
parallel --tag -j1 'ssh -tt localhost perl/catch_wrap perl/catch_all_signals & sleep 1; killall -{} ssh' ::: {1..31}
:, ale usuń „-tt”, a następnie nie będzie działać.-tt
po edycji. Pamiętaj, że jeśli nie uruchomisz polecenia równolegle, ssh odziedziczy terminal, z którego go uruchomisz.-t
, spodziewam się, że to nie zadziała.Aby działało na innych platformach, stało się to ostatecznym rozwiązaniem. Sprawdza, czy klient ssh się rozłączył, a tym samym rodzic stał się pid 1:
źródło