Pourquoi bash ignore-t-il SIGTERM?

10

Parfois, lorsque je veux me déconnecter rapidement, je le fais kill -15 -1. J'ai remarqué que bash ignore SIGTERM.

Je me demande quelle est la justification d'un tel comportement bash ?

Ce n'est pas très UNIX d'ignorer SIGTERM sans une bonne raison, n'est-ce pas?

MISE À JOUR:

même (aucun) effet pour tous:

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

MISE À JOUR2:

De l' homme bash :

Lorsque bash est interactif, en l'absence de tout piège, il ignore SIGTERM

C'est donc fait exprès. Mais pourquoi?

Michał Šrajer
la source
Quel kill utilisez-vous? /bin/killou le shell intégré? Si ce dernier, je suppose que le shell ne se tuera pas avec son propre intégré.
terdon
@terdon: J'ai utilisé la fonction intégrée, mais je ne pense pas que ce soit la raison pour ne pas se tuer soi-même.
Michał Šrajer
1
Si vous souhaitez vous déconnecter rapidement, utilisez Ctrl + d
YoMismo
1
@YoMismo: "déconnexion de la session X"
Michał Šrajer
2
@ MichałŠrajer: Ctrl-Alt-Backspace fait cela pour moi sur Xorg ... vous devrez peut-être l'activer dans xorg.conf, cependant.
Laszlo Valko

Réponses:

10

Tout d'abord, ce n'est pas spécifique à bash. ATT ksh, dash et zsh se comportent de la même manière: ils ignorent SIGTERM et SIGQUIT lors de l'édition en ligne de commande; quant à mksh, il ne quitte pas non plus mais les traite comme SIGINT.

Le manuel ksh et le manuel bash justifient d'ignorer SIGTERM en ces termes:

ce qui kill 0ne tue pas un shell interactif

kill 0tue tous les processus du groupe de processus dans lequel se trouve la coque¹. En résumé, le groupe de processus se compose de tous les processus en cours d'exécution au premier plan sur un terminal, ou de tous les processus en tâche de fond ou suspendus.

Plus précisément, c'est ce qui se passe dans les coques modernes avec contrôle des tâches . Dans de tels shells, kill 0ne serait pas utile, car le shell serait dans un groupe de processus qui lui est propre. Les shells plus anciens (ou les shells modernes après set +m) n'ont pas créé de groupes de processus pour les commandes d'arrière-plan. Vous pouvez donc utiliser la commande kill 0pour supprimer toutes les commandes d'arrière-plan sans vous déconnecter.² Ainsi, la kill 0logique ressemble à une ancienne qui n'est plus justifiée de nos jours mais conservée pour une compatibilité descendante.

Cependant, il existe d'autres situations similaires où l'immunisation de la coquille est utile. Considérez le cas où vous avez des processus monopolisant un terminal et que vous souhaitez les tuer sans vous déconnecter. De nombreux systèmes ont un outil comme celui pkillqui vous permet de tuer les processus en cours d'exécution sur un terminal. Vous pouvez exécuter pkill -t $TTYou pkill -QUIT -t $TTYtuer tous les processus en cours d'exécution sur le terminal actuel, à l'exception du shell qui ignore le signal.

Un shell disparaît normalement soit lorsque l'utilisateur le quitte (avec une commande comme exitou logout), soit lorsque son terminal signale la fin de l'entrée (l'utilisateur peut provoquer cela en appuyant sur Ctrl+ D) ou disparaît complètement. Dans ce dernier cas, le shell reçoit le signal SIGHUP, et il ne l'ignore pas.

Pour votre cas d'utilisation de déconnexion d'une session X, le kill -15 -1fera, car il tue l'émulateur de terminal qui fait que le shell reçoit SIGHUP. Il suffit en fait de tuer le serveur X, mais cela nécessite de trouver son ID de processus. Si vous souhaitez que la même commande fonctionne sur une session de texte, vous pouvez utiliser kill -15 -1; exit. C'est une commande assez dangereuse à avoir à portée de main de toute façon.

¹ Cela ne semble pas être mentionné en règle générale dans les manuels du shell; c'est une caractéristique de l'appel système sous-jacent. Il est mentionné explicitement dans la spécification POSIX .
² De nos jours, pour ce faire, exécutez jobs -lpour voir une liste des travaux avec leur ID de groupe de processus, puis kill -123 -456 …pour tuer les groupes de processus.

Gilles 'SO- arrête d'être méchant'
la source
5

Cela pourrait répondre à votre question:

Lorsque Bash est interactif, en l'absence de tout piège, il ignore SIGTERM (de sorte que 'kill 0' ne tue pas un shell interactif), et SIGINT est intercepté et géré (de sorte que l'attente intégrée est interruptible). Lorsque Bash reçoit un SIGINT, il sort de toutes les boucles en cours d'exécution. Dans tous les cas, Bash ignore SIGQUIT. Si le contrôle des travaux est en vigueur (voir Contrôle des travaux), Bash ignore SIGTTIN, SIGTTOU et SIGTSTP.

Les commandes non intégrées lancées par Bash ont des gestionnaires de signaux définis sur les valeurs héritées par le shell de son parent. Lorsque le contrôle des travaux n'est pas en vigueur, les commandes asynchrones ignorent SIGINT et SIGQUIT en plus de ces gestionnaires hérités. Les commandes exécutées à la suite de la substitution de commandes ignorent les signaux de contrôle des travaux générés par le clavier SIGTTIN, SIGTTOU et SIGTSTP.

Le shell se ferme par défaut à réception d'un SIGHUP. Avant de quitter, un shell interactif renvoie le SIGHUP à toutes les tâches, en cours d'exécution ou arrêtées. Les travaux arrêtés sont envoyés SIGCONT pour s'assurer qu'ils reçoivent le SIGHUP. Pour empêcher le shell d'envoyer le signal SIGHUP à un travail particulier, il doit être supprimé de la table des travaux avec le programme intégré désavoué (voir les commandes de contrôle des travaux) ou marqué pour ne pas recevoir SIGHUP en utilisant disown -h.

Si l'option de shell huponexit a été définie avec shopt (voir The Shopt Builtin), Bash envoie un SIGHUP à toutes les tâches lorsqu'un shell de connexion interactif se ferme.

Si Bash attend la fin d'une commande et reçoit un signal pour lequel un trap a été défini, le trap ne sera pas exécuté tant que la commande ne sera pas terminée. Lorsque Bash attend une commande asynchrone via la fonction d'attente intégrée, la réception d'un signal pour lequel un trap a été défini entraînera le retour immédiat de la fonction interne d'attente avec un état de sortie supérieur à 128, immédiatement après lequel le trap est exécuté.

SOURCE : Le manuel GNU Bash

Petr
la source
Je l'ai cité dans ma mise à jour2. L'homme déclare que bash le fait, mais n'explique pas pourquoi une telle décision. La question demeure - pourquoi?
Michał Šrajer