Warum ignoriert Bash SIGTERM?

10

Manchmal, wenn ich mich schnell abmelden möchte, tue ich das kill -15 -1. Ich habe bemerkt, dass Bash SIGTERM ignoriert.

Ich frage mich, was der Grund für ein solches Bash-Verhalten ist .

Es ist nicht sehr UNIX'y, SIGTERM ohne guten Grund zu ignorieren, nicht wahr?

AKTUALISIEREN:

gleicher (kein) Effekt für alle:

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

UPDATE2:

Von Mann schlagen :

Wenn bash interaktiv ist und keine Fallen vorhanden sind, wird SIGTERM ignoriert

Also wird es absichtlich gemacht. Aber warum?

Michał Šrajer
quelle
Welchen Kill benutzt du? /bin/killoder die Shell eingebaut? Wenn letzteres der Fall ist, schätze ich, dass sich die Shell nicht mit ihrem eigenen eingebauten selbst umbringen wird.
Terdon
@terdon: Ich habe Builtin verwendet, aber ich glaube nicht, dass dies der Grund ist, es nicht selbst zu töten.
Michał Šrajer
1
Wenn Sie sich schnell abmelden möchten, verwenden Sie Strg + d
YoMismo
1
@ YoMismo: "Abmelden von X-Sitzung"
Michał Šrajer
2
@ MichałŠrajer: Strg-Alt-Rücktaste erledigt dies für mich auf Xorg ... Sie müssen es möglicherweise in xorg.conf aktivieren.
Laszlo Valko

Antworten:

10

Erstens ist dies nicht spezifisch für Bash. ATT ksh, dash und zsh verhalten sich gleich: Sie ignorieren SIGTERM und SIGQUIT während der Befehlszeilenausgabe. mksh wird ebenfalls nicht beendet, sondern wie SIGINT behandelt.

Sowohl das ksh-Handbuch als auch das Bash-Handbuch rechtfertigen das Ignorieren von SIGTERM in folgenden Begriffen:

Das kill 0tötet also keine interaktive Shell

kill 0Bricht alle Prozesse in der Prozessgruppe ab , in der sich die Shell befindet¹. Kurz gesagt, die Prozessgruppe besteht aus allen Prozessen, die im Vordergrund auf einem Terminal ausgeführt werden, oder allen Prozessen in einem Hintergrund oder einem angehaltenen Job.

Genauer gesagt passiert dies in modernen Schalen mit Jobkontrolle . In solchen Shells kill 0wäre dies nicht sinnvoll, da sich die Shell in einer eigenen Prozessgruppe befindet. Ältere Shells (oder moderne Shells danach set +m) haben keine Prozessgruppen für Hintergrundbefehle erstellt. Sie können den Befehl also verwenden kill 0, um alle Hintergrundbefehle zu beenden, ohne sich abzumelden.² Daher kill 0sieht die Begründung wie eine alte aus, die heutzutage nicht mehr gerechtfertigt ist, sondern aus Gründen der Abwärtskompatibilität beibehalten wird.

Es gibt jedoch andere ähnliche Situationen, in denen es nützlich ist, die Schale immun zu machen. Stellen Sie sich den Fall vor, in dem Prozesse ein Terminal blockieren und Sie diese beenden möchten, ohne sich abzumelden. Viele Systeme verfügen über ein Tool, mit pkilldem Sie die auf einem Terminal ausgeführten Prozesse beenden können. Sie können alle Prozesse ausführen pkill -t $TTYoder pkill -QUIT -t $TTYbeenden, die auf dem aktuellen Terminal ausgeführt werden, mit Ausnahme der Shell, die das Signal ignoriert.

Eine Shell verschwindet normalerweise entweder, wenn der Benutzer sie verlässt (mit einem Befehl wie exitoder logout) oder wenn ihr Terminal das Ende der Eingabe signalisiert (der Benutzer kann dies durch Drücken von Ctrl+ verursachen D) oder ganz verschwindet. In diesem letzten Fall empfängt die Shell das Signal SIGHUP und ignoriert dieses nicht.

Wenn Sie sich von einer X-Sitzung abmelden, kill -15 -1wird dies ausgeführt, da der Terminalemulator beendet wird, wodurch die Shell SIGHUP empfängt. Es ist in der Tat genug, um den X-Server zu töten, aber das erfordert das Finden seiner Prozess-ID. Wenn Sie möchten, dass derselbe Befehl in einer Textsitzung ausgeführt wird, können Sie ihn verwenden kill -15 -1; exit. Das ist sowieso ein ziemlich gefährlicher Befehl.

¹ Dies scheint in der Regel nicht in Shell-Handbüchern erwähnt zu werden. Dies ist eine Funktion des zugrunde liegenden Systemaufrufs. Es wird ausdrücklich in der POSIX-Spezifikation erwähnt .
² Führen Sie jobs -ldazu heutzutage eine Liste der Jobs mit ihrer Prozessgruppen-ID aus und beenden Sie dann kill -123 -456 …die Prozessgruppen.

Gilles 'SO - hör auf böse zu sein'
quelle
5

Dies könnte Ihre Frage beantworten:

Wenn Bash interaktiv ist und keine Fallen vorhanden sind, ignoriert es SIGTERM (so dass 'kill 0' keine interaktive Shell tötet) und SIGINT wird abgefangen und verarbeitet (so dass das eingebaute Warten unterbrechbar ist). Wenn Bash ein SIGINT empfängt, bricht es aus allen ausführenden Schleifen aus. In allen Fällen ignoriert Bash SIGQUIT. Wenn die Jobsteuerung aktiviert ist (siehe Jobsteuerung), ignoriert Bash SIGTTIN, SIGTTOU und SIGTSTP.

Bei nicht integrierten Befehlen, die von Bash gestartet wurden, werden Signalhandler auf die Werte gesetzt, die die Shell von ihrem übergeordneten Befehl geerbt hat. Wenn die Jobsteuerung nicht aktiviert ist, ignorieren asynchrone Befehle zusätzlich zu diesen geerbten Handlern SIGINT und SIGQUIT. Befehle, die als Ergebnis der Befehlsersetzung ausgeführt werden, ignorieren die von der Tastatur generierten Jobsteuersignale SIGTTIN, SIGTTOU und SIGTSTP.

Die Shell wird standardmäßig nach Erhalt eines SIGHUP beendet. Vor dem Beenden sendet eine interaktive Shell das SIGHUP erneut an alle laufenden oder gestoppten Jobs. Gestoppte Jobs werden SIGCONT gesendet, um sicherzustellen, dass sie das SIGHUP erhalten. Um zu verhindern, dass die Shell das SIGHUP-Signal an einen bestimmten Job sendet, sollte es mit dem eingebauten Disown (siehe Job Control Builtins) aus der Jobtabelle entfernt oder markiert werden, um SIGHUP nicht mit disown -h zu empfangen.

Wenn die huponexit-Shell-Option mit shopt festgelegt wurde (siehe The Shopt Builtin), sendet Bash ein SIGHUP an alle Jobs, wenn eine interaktive Login-Shell beendet wird.

Wenn Bash auf den Abschluss eines Befehls wartet und ein Signal empfängt, für das ein Trap gesetzt wurde, wird der Trap erst ausgeführt, wenn der Befehl abgeschlossen ist. Wenn Bash über das eingebaute Warten auf einen asynchronen Befehl wartet, führt der Empfang eines Signals, für das ein Trap gesetzt wurde, dazu, dass das eingebaute Warten sofort mit einem Exit-Status größer als 128 zurückkehrt, unmittelbar nachdem der Trap ausgeführt wird.

QUELLE : Das GNU Bash Handbuch

Petr
quelle
Ich habe dies in meinem Update2 zitiert. Der Mensch gibt an, dass Bash dies tut, erklärt aber nicht, warum eine solche Entscheidung getroffen wurde. Die Frage bleibt - warum?
Michał Šrajer