Exécuter une commande ou une fonction lorsque SIGINT ou SIGTERM est envoyé au script parent lui-même, pas aux processus enfants

11

Disons que j'ai ça script.sh

#!/bin/bash
exit_script() {
    echo "Printing something special!"
    echo "Maybe executing other commands!"
    kill -- -$$ # Sends SIGTERM to child/sub processes
}

echo "Some other text"
#other commands here
sleep infinity

Je veux script.shexécuter la fonction exit_scriptchaque fois qu'elle reçoit SIGINTou SIGTERM Par exemple:

killall script.sh # it will send SIGTERM to my script

et je veux que mon script exécute cela

exit_script() {
    echo "Printing something special!"
    echo "Maybe executing other commands!"
    kill -- -$$ # Sends SIGTERM to child/sub processes
}

J'ai essayé d'implémenter cette fonctionnalité en utilisant trap

trap exit_script SIGINT SIGTERM

La personne qui a répondu à ma question m'a donné tort.
mais cela n'a pas fonctionné car il trapsemble ne réagir qu'aux signaux envoyés aux processus enfants / sous. En tant que débutant, je ne pouvais pas déchiffrer trapla page de manuel de donc j'ai probablement raté la solution.

Je suppose que c'est ce que font les "vrais" programmes comme Chromium lorsque vous les envoyez SIGTERM

Depuis https://major.io/2010/03/18/sigterm-vs-sigkill/

L'application peut déterminer ce qu'elle veut faire une fois qu'un SIGTERM est reçu. Bien que la plupart des applications nettoient leurs ressources et s'arrêtent, certaines peuvent ne pas le faire.

bosa djo
la source
2
jure généralement considéré comme inapprécié pour un discours respectueux
cat
modifier la suggestion approuvée ok, ok done, pas de plaisir je l'ai
bosa djo
ce n'est pas que le plaisir n'est pas permis, c'est juste que c'est considéré comme offensant
cat
1
@cat J'ai réfléchi à votre argument et vous avez raison, désolé pour ma tromperie
bosa djo

Réponses:

15

trapréagit aux signaux du processus appelant lui-même. Mais vous devez l'appeler avant la réception du signal. Je veux dire, au début de votre script.

De plus, si vous souhaitez utiliser kill -- -$$, qui envoie également le signal à votre script, vous devez effacer le piège avant d'exécuter le kill ou vous terminerez avec une boucle kill && trap infinie .

Par exemple:

#!/bin/bash
exit_script() {
    echo "Printing something special!"
    echo "Maybe executing other commands!"
    trap - SIGINT SIGTERM # clear the trap
    kill -- -$$ # Sends SIGTERM to child/sub processes
}

trap exit_script SIGINT SIGTERM

echo "Some other text"
#other commands here
sleep infinity

Comme expliqué dans les commentaires, le problème est que le script reçoit le signal mais attend la fin du programme de veille avant de traiter le signal reçu. Donc, vous devez tuer les processus enfants (le processus de veille dans ce cas) afin d'exécuter l'action d'interruption. Vous pouvez le faire avec quelque chose comme ce qui suit:

kill -- -$(pgrep script.sh)

Ou comme indiqué dans les commentaires:

killall -g script.sh
zuazo
la source
1
Il me manque probablement quelque chose car cela ne fonctionne pas, voici ce que je fais. script.sh &; killall script.sh mais cela ne fait rien.
bosa djo
J'exécute le script.sh &; # alors je fais mes affaires; killall script.sh et il ne tue pas script.sh
bosa djo
1
Le problème est probablement que le script reçoit le signal mais attend que le programme de veille se termine avant de le traiter. Essayez également ./script.sh & sleep 1 && kill -- -$(pgrep script.sh)d'envoyer un signal d'arrêt aux processus enfants de votre script.
zuazo
@zuazo Vous devez ajouter cette information intéressante et importante à votre réponse :)
cat
1
Bien, bosa djo. J'ai ajouté votre solution alternative à la réponse ;-)
zuazo