Jak zakończyć zdalnie nazywane „tail-f”, gdy połączenie jest zamknięte?

24

Właśnie zauważyłem, że jeśli wykonam ssh user@remote_host tail -f /some/file, to tail -f /some/filedalej działa na remote_host nawet jeśli połączenie ssh jest zamknięte!

Tak więc po kilku połączeniach i rozłączeniach tail -f /some/filerośnie liczba uruchomionych . Jak zakończyć tail -fpołączenie, gdy połączenie ssh jest zamknięte?

Dmitry Frank
źródło

Odpowiedzi:

33

W

ssh host tail -f file

sshKlient łączy się z sshdserwerem na hostpośrednictwem połączenia TCP. sshddziała tail -fz przekierowaniem standardu na potok. sshdodczytuje to, co pochodzi z drugiego końca potoku i hermetyzuje go w protokole sshd, aby wysłać do sshklienta. (z rshd, tailstdout byłby bezpośrednio gniazdem, ale sshddodaje szyfrowanie i jest w stanie multipleksować kilka strumieni (jak dla przekierowania portu / agenta / X11 / tunelu, stderr) na jednym połączeniu TCP, więc musi uciekać się do potoków).

Po naciśnięciu CTRL-C do sshklienta wysyłany jest SIGINT . To powoduje sshśmierć. Po śmierci połączenie TCP zostaje zamknięte. A zatem host, sshdmatryce, jak również. tailnie jest zabity, ale jego stdout jest teraz rurą bez czytnika na drugim końcu. Tak więc, następnym razem, gdy napisze coś na swoje standardowe wyjście, otrzyma SIGPIPE i umrze.

W:

ssh -t host 'tail -f file'

To to samo, z tą różnicą, że zamiast być z potokiem komunikacja między sshdi tailodbywa się za pośrednictwem pseudo-terminala. tailstdout jest pseudo-terminalem slave (podobnym /dev/pts/12) i cokolwiek tailzapisuje readsię po stronie master (być może zmodyfikowane przez dyscyplinę linii tty) sshdi wysyłane jest do enkapsulacji do sshklienta.

Po stronie klienta -t, sshprzełącza terminal w rawtryb. W szczególności wyłącza to tryb kanoniczny terminala i obsługę sygnału terminala.

Tak więc, gdy naciśniesz Ctrl+C, zamiast dyscypliny linii terminalu klienta wysyłającej SIGINT do sshzadania, to po prostu wysyła ^Cznak przez połączenie sshdi sshdzapisuje go ^Cdo strony głównej zdalnego terminala. A dyscyplina liniowa zdalnego terminala wysyła SIGINTdo tail. tailnastępnie umiera, sshdopuszcza i zamyka połączenie i sshprzerywa połączenie (jeśli nie jest zajęte przekazywaniem portów lub innymi).

Ponadto, -tjeśli sshklient umrze (na przykład jeśli wejdziesz ~.), połączenie zostanie zamknięte i sshdumrze. W rezultacie SIGHUP zostanie wysłany do tail.

Teraz uważaj, że używanie -tma skutki uboczne. Na przykład przy domyślnych ustawieniach terminala \nznaki są konwertowane na \r\ni w zależności od systemu zdalnego może się zdarzyć więcej rzeczy, więc możesz chcieć wydać stty -opost(aby wyłączyć przetwarzanie końcowe danych wyjściowych) na zdalnym hoście, jeśli dane wyjściowe nie są przeznaczone terminal:

$ 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

Kolejną wadą używania -t/ -ttjest to, że stdout i stderr nie są zróżnicowane na kliencie. Zarówno stdout, jak i stderr polecenia zdalnego zostaną zapisane sshna stdout klienta:

$ ssh localhost ls /x  | wc -l
ls: cannot access /x: No such file or directory
0
$ ssh -t localhost ls /x | wc -l
1
Stéphane Chazelas
źródło
Dziękuję bardzo za tak szczegółowe wyjaśnienie! Chciałbym przyjąć dwie odpowiedzi ..
Dmitry Frank
„z -t, jeśli sshklient umrze (na przykład, jeśli wejdziesz ~.)” „Co jest ~.znowu?
x-yuri
1
@ x-yuri, ~.to sekwencja ucieczki wprowadzana w celu odłączenia klienta. Zobacz man sshszczegóły.
Stéphane Chazelas
11

Potrzebny jest przydział terminali po stronie zdalnej:

ssh -t user@remote_host tail -f /some/file

lub nawet

ssh -tt user@remote_host tail -f /some/file
Hauke ​​Laging
źródło
1
Dzięki, oba -tlub -ttdziała. Ale nadal nie rozumiem prawdziwej przyczyny tego: powiedzmy, że kiedy wywołuję powłokę zdalnie i zamykam połączenie, powłoka zostaje zakończona. Ale tail -fnie jest. Oczywiście już czytałem o -topcji w man ssh, ale to niewiele pomogło. Wygląda na to, że nie rozumiem niektórych generyków i byłbym szczęśliwy, gdybyś zasugerował kilka dokumentów do przeczytania na ten temat lub prawdopodobnie sam to wyjaśnił. Dzięki!
Dmitry Frank
2
@DmitryFrank Rozumiem tak: jeśli połączenie zostanie zerwane, zostanie sshdwysłany komunikat SIGHUP. Ale tam, gdzie nie ma terminala, nie może być rozłączenia połączenia terminala ...
Hauke ​​Laging
Dzięki, przeczytam o tym SIGHUPi inne sygnały, wciąż nic o tym nie wiem.
Dmitry Frank
fyi: Właśnie próbowałem uruchomić tail -f, a następnie otworzyłem htopi wysłałem SIGHUPdo niego (naciskając F9-> 1-> Enter) i tail -fzakończyłem! Powód powinien być inny ...
Dmitry Frank
3
@DmitryFrank Źle zrozumiałeś problem. Problem nie polega na tym, tailże nie zareagowałby SIGHUP. Problem polega na tym, że SIGHUP** nie jest wysyłany do tailbez pseudo terminala. Możesz to zobaczyć, dołączając stracesię tailw obu przypadkach.
Hauke ​​Laging