Як припинити віддалену назву "хвіст -f", коли з'єднання закрите?


24

Я щойно помітив, що якщо я виконую ssh user@remote_host tail -f /some/file, то tail -f /some/fileпродовжує працювати на remote_host, навіть якщо ssh-з'єднання закрито!

Отже, після декількох підключень та відключень кількість бігів tail -f /some/fileзростає. Як насправді припинити, tail -fколи закрито ssh-з'єднання?

Відповіді:


33

В

ssh host tail -f file

sshКлієнт підключається до sshdсервера на hostза допомогою бездротової технології TCP. sshdпроходить tail -fзі своїм виступом, перенаправленим на трубу. sshdчитає, що надходить з іншого кінця труби, і інкапсулює його в протокол sshd для надсилання sshклієнту. (з rshd, tailstdout був би сокетом безпосередньо, але sshdдодає шифрування і може мультиплексувати декілька потоків (наприклад, для переходу на порт / агент / X11 / тунель, stderr) на одному TCP-з'єднанні, тому доводиться вдаватися до труб).

Коли ви натискаєте CTRL-C, sshклієнту надсилається SIGINT . Це змушує sshпомерти. Після відмирання TCP-з'єднання закривається. А отже, hostі sshdвмирає. tailне вбита, але тепер її виступ - це труба без читача на іншому кінці. Отже, наступного разу, коли він щось напише до свого stdout, він отримає ПІДПИС і помре.

В:

ssh -t host 'tail -f file'

Це те саме, за винятком того, що замість того, щоб бути з трубою, зв'язок між sshdі tailздійснюється через псевдотермінал. tail's stoutout' є псевдо-терміналом рабовласницького типу (як /dev/pts/12) і що б tailтам не readбуло написано на головній стороні (можливо, модифікованій дисципліною Tty line), sshdнадісланим інкапсульованим sshклієнтом.

На стороні клієнта, з -t, sshпереводить термінал в rawрежим. Зокрема, це вимикає канальний режим терміналу та обробку сигналу терміналу.

Отже, коли ви натискаєте Ctrl+Cзамість термінальної лінії клієнтської лінії, що надсилає SIGINT на sshзавдання, він просто надсилає ^Cперсонажа через з'єднання sshdі sshdзаписує ^Cйого на головну сторону віддаленого терміналу. І дисципліна лінії віддаленого терміналу посилає SIGINTна tail. tailпотім помирає, sshdвиходить і закриває з'єднання та sshприпиняється (якщо воно іншим чином ще не зайняте переадресацією портів чи іншим).

Також, -tякщо sshклієнт помирає (наприклад, якщо ви входите ~.), з'єднання закривається і sshdвідмирає. Як результат, SIGHUP буде надісланий на tail.

Тепер будьте уважні, що використання -tмає побічні ефекти. Наприклад, з налаштуваннями терміналу за замовчуванням \nсимволи перетворюються на \r\nінші речі, і це може траплятися більше, залежно від віддаленої системи, тому ви, можливо, захочете видати stty -opost(відключити післяобробну обробку виводу) на віддаленому хості, якщо цей вихід не призначений для термінал:

$ 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

Ще одним недоліком використання -t/ -ttє те, що stdout та stderr не відрізняються від клієнта. І stdout, і stderr віддаленої команди будуть записані в sshstdout клієнта:

$ ssh localhost ls /x  | wc -l
ls: cannot access /x: No such file or directory
0
$ ssh -t localhost ls /x | wc -l
1

Дуже дякую за таке детальне пояснення! Я хотів би прийняти дві відповіді ..
Дмитро Френк

-t, якщо sshклієнт помирає (наприклад, якщо ви введете ~.)" Що ~.знову?
x-yuri

1
@ x-yuri ~.- це послідовність евакуації, яку ви вводите для відключення клієнта. Детальніше man sshдив.
Стефан Шазелас

11

Вам потрібно розподіл терміналу на віддаленій стороні:

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

або навіть

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

1
Спасибі, як -tі -ttпрацює. Але я досі не можу зрозуміти справжню причину цього: скажімо, коли я віддалено дзвоню оболонці та закриваю з'єднання, оболонка припиняється. Але tail -fце не так. Звичайно, я вже читав про -tваріант в man ssh, але це не дуже допомогло. Здається, я не розумію деяких дженериків, і я буду радий, якщо ви запропонуєте деякі документи прочитати про це чи, можливо, поясніть самі. Спасибі!
Дмитро Франк

2
@DmitryFrank Моє розуміння таке: Якщо з'єднання розривається, то sshdнадсилається a SIGHUP. Але там, де немає терміналу, не може бути з’єднання підключення до терміналу ...
Hauke ​​Laging

Дякую, я прочитаю про SIGHUPта інші сигнали, все ще майже нічого про це не знаю.
Дмитро Франк

fyi: Я просто спробував запустити tail -f, потім я відкрив htopі надіслав SIGHUPдо нього (натискаючи F9-> 1-> Enter), і tail -fзакінчується! Отже, причина має бути дещо інша ..
Дмитро Френк

3
@DmitryFrank Ви неправильно зрозуміли проблему. Проблема не в тому, на що tailб не відреагували SIGHUP. Проблема в тому, що SIGHUP** не надсилається " tailбез псевдотерміналу. Ви можете це побачити, приєднавшись straceдо tailобох випадків.
Hauke ​​Laging
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.