Làm thế nào để chấm dứt từ xa được gọi là đuôi đuôi -f khi kết nối bị đóng?


24

Tôi chỉ nhận thấy rằng nếu tôi thực thi ssh user@remote_host tail -f /some/file, thì hãy tail -f /some/filetiếp tục chạy trên remote_host ngay cả khi kết nối ssh bị đóng!

Vì vậy, sau vài lần kết nối và ngắt kết nối, số lần chạy tail -f /some/filetăng lên. Làm thế nào để thực sự chấm dứt tail -fkhi kết nối ssh bị đóng?

Câu trả lời:


33

Trong

ssh host tail -f file

Máy sshkhách kết nối với sshdmáy chủ hostqua kết nối TCP. sshdchạy tail -fvới thiết bị xuất chuẩn của nó được chuyển hướng đến một đường ống. sshdđọc những gì đến từ đầu kia của ống và gói nó trong giao thức sshd để gửi cho sshkhách hàng. (với rshd, tailthiết bị xuất chuẩn sẽ là ổ cắm trực tiếp, nhưng sshdthêm mã hóa và có thể ghép nhiều luồng (như chuyển hướng cổng / tác nhân / X11 / đường hầm, stderr) trên một kết nối TCP duy nhất do đó phải dùng đến đường ống).

Khi bạn nhấn CTRL-C, SIGINT được gửi đến sshmáy khách. Điều đó gây ra sshcái chết. Khi chết, kết nối TCP được đóng lại. Và do đó, trên host, sshdchết là tốt. tailkhông bị giết, nhưng thiết bị xuất chuẩn của nó bây giờ là một ống không có đầu đọc ở đầu kia. Vì vậy, lần tiếp theo nó viết một cái gì đó vào thiết bị xuất chuẩn của mình, nó sẽ nhận được SIGPIPE và chết.

Trong:

ssh -t host 'tail -f file'

Đó là điều tương tự ngoại trừ thay vì ở với một đường ống, giao tiếp giữa sshdtailthông qua một thiết bị đầu cuối giả. tailStdout là một thiết bị đầu cuối giả (như /dev/pts/12) và bất cứ thứ gì được tailviết ở readphía chủ (có thể được sửa đổi bởi kỷ luật dòng tty) bằng cách sshdgửi và đóng gói cho sshkhách hàng.

Về phía khách hàng, với -t, sshđặt thiết bị đầu cuối ở rawchế độ. Cụ thể, điều đó vô hiệu hóa chế độ chính tắc đầu cuối và xử lý tín hiệu đầu cuối.

Vì vậy, khi bạn nhấn Ctrl+C, thay vì kỷ luật dòng thiết bị đầu cuối của khách hàng gửi SIGINT đến sshcông việc, chỉ cần gửi ^Cký tự qua kết nối đến sshdsshdghi nó ^Cvào phía chính của thiết bị đầu cuối từ xa. Và kỷ luật dòng của thiết bị đầu cuối từ xa gửi SIGINTđến tail. tailsau đó chết, sshdthoát ra và đóng kết nối và sshchấm dứt (nếu nó vẫn không bận rộn với chuyển tiếp cổng hoặc khác).

Ngoài ra, với -t, nếu sshmáy khách chết (ví dụ nếu bạn nhập ~.), kết nối sẽ bị đóng và sshdchết. Do đó, một SIGHUP sẽ được gửi đến tail.

Bây giờ, hãy cẩn thận rằng sử dụng -tcó tác dụng phụ. Chẳng hạn, với cài đặt thiết bị đầu cuối mặc định, các \nký tự được chuyển đổi thành \r\nnhiều thứ có thể xảy ra tùy thuộc vào hệ thống từ xa, do đó bạn có thể muốn phát hành stty -opost(để tắt xử lý hậu kỳ đầu ra) trên máy chủ từ xa nếu đầu ra đó không dành cho một thiết bị đầu cuối:

$ 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

Một nhược điểm khác của việc sử dụng -t/ -ttlà stdout và stderr không được phân biệt trên máy khách. Cả thiết bị xuất chuẩn và thiết bị xuất chuẩn của lệnh từ xa sẽ được ghi vào sshthiết bị xuất chuẩn của máy khách:

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

Cảm ơn bạn rất nhiều vì một lời giải thích chi tiết như vậy! Tôi ước tôi có thể chấp nhận hai câu trả lời ..
Dmitry Frank

"với -t, nếu sshmáy khách chết (ví dụ nếu bạn nhập ~.)" ~.Lại là gì?
x-yuri

1
@ x-yuri, ~.là chuỗi thoát bạn nhập để ngắt kết nối máy khách. Xem man sshđể biết chi tiết.
Stéphane Chazelas

11

Bạn cần phân bổ thiết bị đầu cuối ở phía xa:

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

hoặc thậm chí

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

1
Cảm ơn, cả hai -thoặc -ttcông việc. Nhưng tôi vẫn không thể hiểu lý do thực sự của việc này: giả sử, khi tôi gọi shell từ xa và đóng kết nối, shell bị chấm dứt. Nhưng tail -fkhông phải. Tất nhiên tôi đã đọc về -ttùy chọn trong man ssh, nhưng nó không giúp được gì nhiều. Có vẻ như tôi không hiểu một số khái quát, và tôi rất vui nếu bạn đề xuất một số tài liệu để đọc về nó, hoặc có thể tự giải thích nó. Cảm ơn!
Dmitry Frank

2
@DmitryFrank Sự hiểu biết của tôi là thế này: Nếu kết nối bị ngắt thì sshdsẽ gửi a SIGHUP. Nhưng nếu không có thiết bị đầu cuối thì không thể có kết nối thiết bị đầu cuối ...
Hauke ​​Laging

Cảm ơn, tôi sẽ đọc về SIGHUPvà các tín hiệu khác, vẫn gần như không biết gì về nó.
Dmitry Frank

fyi: Tôi vừa thử chạy tail -f, sau đó tôi đã mở htopvà gửi SIGHUPcho nó (bằng cách nhấn F9-> 1-> Enter), và tail -fbị chấm dứt! Vì vậy, lý do nên có một số khác biệt ..
Dmitry Frank

3
@DmitryFrank Bạn đã hiểu nhầm vấn đề. Vấn đề không phảitailsẽ không phản ứng SIGHUP. Vấn đề là SIGHUP** không được gửi đến tailmà không có thiết bị đầu cuối giả. Bạn có thể thấy rằng bằng cách gắn stracevào tailtrong cả hai trường hợp.
Hauke ​​Laging
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.