Tại sao bash bỏ qua SIGTERM?


10

Đôi khi tôi muốn đăng xuất nhanh chóng kill -15 -1. Tôi đã nhận thấy rằng bash đang bỏ qua SIGTERM.

Tôi tự hỏi những gì hợp lý cho hành vi bash như vậy ?

Không phải là rất UNIX để bỏ qua SIGTERM mà không có lý do chính đáng, phải không?

CẬP NHẬT:

hiệu ứng tương tự (không) cho tất cả:

$ kill -TERM $$
$ type kill
kill is a shell builtin
$ command kill -TERM $$
$ /bin/kill -TERM $$

CẬP NHẬT2:

Từ người đàn ông bash :

Khi bash tương tác, trong trường hợp không có bẫy, nó sẽ bỏ qua SIGTERM

Vì vậy, nó được thực hiện trên mục đích. Nhưng tại sao?


Bạn đang sử dụng kill nào? /bin/killhoặc vỏ dựng sẵn? Nếu sau này, tôi đoán rằng cái vỏ sẽ không tự sát bằng chính nó.
terdon

@terdon: Tôi đã sử dụng nội dung, nhưng tôi không nghĩ đó là lý do để không tự sát.
Michał rajer

1
Nếu bạn muốn đăng xuất nhanh chóng thì hãy sử dụng Ctrl + d
YoMismo

1
@YoMismo: "đăng xuất từ ​​phiên X"
Michał rajer

2
@ MichałŠrajer: Ctrl-Alt-Backspace thực hiện điều này cho tôi trên Xorg ... tuy nhiên, bạn có thể phải bật nó trong xorg.conf.
Laszlo Valko

Câu trả lời:


10

Đầu tiên, điều này không cụ thể đối với bash. ATT ksh, dash và zsh hoạt động theo cùng một cách: họ bỏ qua SIGTERM và SIGQUIT trong phiên bản dòng lệnh; đối với mksh, nó cũng không bỏ nhưng đối xử với họ như SIGINT.

Cả hướng dẫn sử dụng ksh và hướng dẫn bash đều biện minh cho việc bỏ qua SIGTERM trong các điều khoản sau:

vì vậy mà kill 0không giết được vỏ tương tác

kill 0Giết tất cả các quy trình trong nhóm quy trình mà shell nằm trong. Tóm lại, nhóm quy trình bao gồm tất cả các quy trình đang chạy ở nền trước trên thiết bị đầu cuối hoặc tất cả các quy trình trong nền hoặc công việc bị đình chỉ.

Chính xác hơn, đây là những gì xảy ra trong vỏ hiện đại với kiểm soát công việc . Trong các shell như vậy, kill 0sẽ không hữu ích, vì shell sẽ nằm trong một nhóm quy trình của riêng nó. Các shell cũ hơn (hoặc các shell hiện đại sau set +m) không tạo các nhóm quy trình cho các lệnh nền. Vì vậy, bạn có thể sử dụng lệnh kill 0để giết tất cả các lệnh nền mà không bị đăng xuất .² Do đó, kill 0cơ sở lý luận trông giống như một lệnh cũ không còn hợp lý ngày nay mà vẫn giữ được tính tương thích ngược.

Tuy nhiên, có những tình huống tương tự khác trong đó làm cho vỏ miễn dịch là hữu ích. Hãy xem xét trường hợp bạn có các quy trình ăn cắp một thiết bị đầu cuối và bạn muốn giết chúng mà không cần đăng xuất. Nhiều hệ thống có một công cụ pkillcho phép bạn tiêu diệt các tiến trình đang chạy trên thiết bị đầu cuối. Bạn có thể chạy pkill -t $TTYhoặc pkill -QUIT -t $TTYđể giết tất cả các quá trình đang chạy trên thiết bị đầu cuối hiện tại, ngoại trừ lớp vỏ bỏ qua tín hiệu.

Một shell thường biến mất khi người dùng thoát nó (với lệnh như exithoặc logout) hoặc khi thiết bị đầu cuối báo hiệu kết thúc đầu vào (người dùng có thể gây ra điều này bằng cách nhấn Ctrl+ D) hoặc biến mất hoàn toàn. Trong trường hợp cuối cùng này, shell nhận được tín hiệu SIGHUP và nó không bỏ qua cái đó.

Đối với trường hợp sử dụng của bạn khi đăng xuất khỏi phiên X, kill -15 -1sẽ thực hiện việc đó, vì nó sẽ giết chết trình giả lập thiết bị đầu cuối khiến cho vỏ nhận được SIGHUP. Thực tế nó đủ để giết máy chủ X, nhưng điều đó đòi hỏi phải tìm ID tiến trình của nó. Nếu bạn muốn cùng một lệnh hoạt động trên một phiên văn bản, bạn có thể sử dụng kill -15 -1; exit. Dù sao đó cũng là một lệnh nguy hiểm phải có trong tầm tay bạn.

¹ này dường như không được đề cập trong hướng dẫn sử dụng vỏ như một quy luật; đó là một tính năng của cuộc gọi hệ thống cơ bản. Nó được đề cập rõ ràng trong đặc tả POSIX .
² Ngày nay, để làm điều đó, hãy chạy jobs -lđể xem danh sách các công việc với ID nhóm quy trình của họ, sau đó kill -123 -456 …để giết các nhóm quy trình.


5

Điều này có thể trả lời câu hỏi của bạn:

Khi Bash tương tác, trong trường hợp không có bất kỳ bẫy nào, nó sẽ bỏ qua SIGTERM (để 'kill 0' không giết được vỏ tương tác), và SIGINT bị bắt và xử lý (do đó, nội dung chờ đợi bị gián đoạn). Khi Bash nhận được SIGINT, nó thoát ra khỏi bất kỳ vòng lặp thực thi nào. Trong mọi trường hợp, Bash bỏ qua SIGQUIT. Nếu kiểm soát công việc có hiệu lực (xem Kiểm soát công việc), Bash sẽ bỏ qua SIGTTIN, SIGTTOU và SIGTSTP.

Các lệnh không dựng sẵn được bắt đầu bởi Bash có các trình xử lý tín hiệu được đặt thành các giá trị được kế thừa bởi trình bao từ cha của nó. Khi điều khiển công việc không có hiệu lực, các lệnh không đồng bộ sẽ bỏ qua SIGINT và SIGQUIT ngoài các trình xử lý được kế thừa này. Các lệnh chạy như là kết quả của việc thay thế lệnh bỏ qua các tín hiệu điều khiển công việc do bàn phím tạo ra SIGTTIN, SIGTTOU và SIGTSTP.

Shell thoát theo mặc định khi nhận được SIGHUP. Trước khi thoát, một vỏ tương tác gửi lại SIGHUP cho tất cả các công việc, đang chạy hoặc dừng. Các công việc đã dừng được gửi SIGCONT để đảm bảo rằng họ nhận được SIGHUP. Để ngăn vỏ gửi tín hiệu SIGHUP đến một công việc cụ thể, nó phải được xóa khỏi bảng công việc với phần dựng sẵn (xem phần Điều khiển công việc) hoặc được đánh dấu để không nhận SIGHUP bằng cách sử dụng từ chối -h.

Nếu tùy chọn vỏ huponexit đã được đặt với shopt (xem Cửa hàng được xây dựng), Bash sẽ gửi SIGHUP cho tất cả các công việc khi thoát khỏi vỏ đăng nhập tương tác.

Nếu Bash đang chờ lệnh hoàn thành và nhận được tín hiệu đặt bẫy, bẫy sẽ không được thực thi cho đến khi lệnh hoàn thành. Khi Bash đang chờ lệnh không đồng bộ thông qua nội dung chờ, việc nhận tín hiệu đặt bẫy sẽ khiến cho lệnh chờ được trả về ngay lập tức với trạng thái thoát lớn hơn 128, ngay sau đó bẫy được thực thi.

NGUỒN : Hướng dẫn sử dụng GNU Bash


Tôi đã trích dẫn điều này trong update2 của tôi. Man nói rằng bash đang làm như vậy, nhưng không giải thích tại sao quyết định như vậy. Câu hỏi vẫn còn - tại sao?
Michał rajer
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.