Dlaczego bash ignoruje SIGTERM?

10

Czasami chcę szybko się wylogować kill -15 -1. Zauważyłem, że bash ignoruje SIGTERM.

Zastanawiam się, jakie jest uzasadnienie takiego bashowego zachowania ?

Zignorowanie SIGTERM bez uzasadnionego powodu nie jest w UNIX-ie nieprawdaż, prawda?

AKTUALIZACJA:

taki sam (nie) efekt dla wszystkich:

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

AKTUALIZACJA 2:

From man bash :

Gdy bash jest interaktywny, przy braku pułapek, ignoruje SIGTERM

Więc jest to zrobione celowo. Ale dlaczego?

Michał Šrajer
źródło
Którego zabijasz? /bin/killczy wbudowana powłoka? Jeśli to drugie, domyślam się, że powłoka nie zabije się z własnym wbudowaniem.
terdon
@terdon: Użyłem wbudowanego, ale nie sądzę, że to jest powód, aby nie zabijać go samodzielnie.
Michał Šrajer
1
Jeśli chcesz się szybko wylogować, użyj Ctrl + d
YoMismo
1
@YoMismo: „wyloguj się z sesji X”
Michał Šrajer
2
@ MichałŠrajer: Ctrl-Alt-Backspace robi to dla mnie na Xorgu ... jednak może być konieczne włączenie go w xorg.conf.
Laszlo Valko

Odpowiedzi:

10

Po pierwsze, nie jest to specyficzne dla bash. ATT ksh, dash i zsh zachowują się w ten sam sposób: ignorują SIGTERM i SIGQUIT podczas edycji wiersza poleceń; co do mksh, to również nie wychodzi, ale traktuje je jak SIGINT.

Zarówno podręcznik ksh, jak i podręcznik bash uzasadniają ignorowanie SIGTERM w następujących terminach:

dzięki czemu kill 0nie zabija interaktywnej powłoki

kill 0zabija wszystkie procesy w grupie procesów , w której znajduje się powłoka¹. W skrócie, grupa procesów składa się ze wszystkich procesów działających na pierwszym planie na terminalu lub wszystkich procesów w tle lub zawieszonym zadaniu.

Mówiąc dokładniej, dzieje się tak w nowoczesnych powłokach z kontrolą zadań . W takich powłokach kill 0nie byłoby to przydatne, ponieważ powłoka byłaby w swojej własnej grupie procesów. Starsze powłoki (lub współczesne po nich set +m) nie tworzyły grup procesów dla poleceń w tle. Można więc użyć tego polecenia, kill 0aby zabić wszystkie polecenia w tle bez wylogowania. ² W związku z tym kill 0uzasadnienie wygląda jak stare, które nie jest już uzasadnione, ale zachowuje zgodność wsteczną.

Istnieją jednak inne podobne sytuacje, w których uodpornienie skorupy jest przydatne. Rozważ przypadek, w którym procesy blokują terminal i chcesz je zabić bez wylogowania. Wiele systemów ma takie narzędzie, pkillktóre pozwala zabijać procesy uruchomione na terminalu. Możesz uruchomić pkill -t $TTYlub pkill -QUIT -t $TTYzabić wszystkie procesy uruchomione na bieżącym terminalu, z wyjątkiem powłoki, która ignoruje sygnał.

Powłoka zwykle znika albo, gdy użytkownik ją opuści (za pomocą polecenia typu exitlub logout), albo gdy jej terminal sygnalizuje koniec wejścia (użytkownik może to spowodować, naciskając Ctrl+ D) lub całkowicie znika. W tym ostatnim przypadku powłoka odbiera sygnał SIGHUP i tego nie ignoruje.

Zrobisz to na przykład w przypadku wylogowania z sesji X kill -15 -1, ponieważ zabija emulator terminala, który powoduje, że powłoka odbiera SIGHUP. W rzeczywistości wystarczy zabić serwer X, ale to wymaga znalezienia jego identyfikatora procesu. Jeśli chcesz, aby to samo polecenie działało w sesji tekstowej, możesz użyć kill -15 -1; exit. W każdym razie jest to dość niebezpieczne polecenie.

¹ Wydaje się, że nie jest to z reguły wspomniane w podręcznikach powłoki; jest to funkcja podstawowego wywołania systemowego. Jest to wyraźnie wymienione w specyfikacji POSIX .
² W tym jobs -lcelu biegnij, aby zobaczyć listę zadań z ich identyfikatorem grupy procesów, a następnie kill -123 -456 …zabić grupy procesów.

Gilles „SO- przestań być zły”
źródło
5

To może odpowiedzieć na twoje pytanie:

Gdy Bash jest interaktywny, przy braku pułapek, ignoruje SIGTERM (tak, że „kill 0” nie zabija interaktywnej powłoki), a SIGINT jest przechwytywany i obsługiwany (tak, że wbudowane oczekiwanie jest przerywane). Gdy Bash otrzymuje SIGINT, wyrywa się z wszelkich wykonanych pętli. We wszystkich przypadkach Bash ignoruje SIGQUIT. Jeśli kontrola zadań jest aktywna (patrz Kontrola zadań), Bash ignoruje SIGTTIN, SIGTTOU i SIGTSTP.

Wbudowane polecenia uruchamiane przez Bash mają procedury obsługi sygnałów ustawione na wartości odziedziczone przez powłokę od jej rodzica. Gdy kontrola zadań nie jest aktywna, polecenia asynchroniczne ignorują SIGINT i SIGQUIT oprócz tych odziedziczonych programów obsługi. Polecenia uruchamiane w wyniku podstawienia poleceń ignorują generowane przez klawiaturę sygnały kontrolne zadań SIGTTIN, SIGTTOU i SIGTSTP.

Powłoka wychodzi domyślnie po otrzymaniu SIGHUP. Przed wyjściem interaktywna powłoka ponownie wysyła SIGHUP do wszystkich zadań, uruchomionych lub zatrzymanych. Zatrzymane zadania są wysyłane SIGCONT, aby upewnić się, że otrzymają SIGHUP. Aby zapobiec wysyłaniu przez powłokę sygnału SIGHUP do określonego zadania, należy go usunąć z tabeli zadań z wbudowanym disown (patrz Wbudowane funkcje kontroli zadań) lub zaznaczyć, że nie może odbierać SIGHUP przy użyciu disown -h.

Jeśli opcja powłoki huponexit została ustawiona w shopt (patrz Wbudowane Shopt), Bash wysyła SIGHUP do wszystkich zadań, gdy kończy się interaktywna powłoka logowania.

Jeśli Bash czeka na zakończenie komendy i odbiera sygnał, dla którego ustawiono pułapkę, pułapka nie zostanie wykonana, dopóki polecenie się nie zakończy. Gdy Bash czeka na polecenie asynchroniczne poprzez wbudowane oczekiwanie, odbiór sygnału, dla którego ustawiono pułapkę, spowoduje natychmiastowe powrót wbudowanego oczekiwania ze statusem wyjścia większym niż 128, natychmiast po którym pułapka zostanie wykonana.

ŹRÓDŁO : Podręcznik GNU Bash

Petr
źródło
Cytowałem to w mojej aktualizacji2. Mężczyzna twierdzi, że robi to bash, ale nie wyjaśnia, dlaczego taka decyzja. Pozostaje pytanie - dlaczego?
Michał Šrajer,