Objectifs
- Comprendre ce qu’est un signal et connaître les signaux les plus courants (
SIGINT,SIGTERM). - Intercepter ces signaux avec la commande
trappour exécuter une action spécifique. - Créer des scripts robustes qui effectuent des opérations de nettoyage (ex: supprimer des fichiers temporaires) avant de se terminer, même en cas d’interruption.
Explications détaillées
Notions clés
Les Signaux : Messages du Système
Un signal est une notification envoyée par le système d’exploitation à un processus pour l’informer d’un événement. Un script peut choisir d’ignorer un signal, d’adopter le comportement par défaut, ou d’exécuter une action personnalisée.
Signaux courants :
SIGINT(Signal Interrupt, N°2) : Envoyé lorsque vous appuyez surCtrl+C. L’action par défaut est de terminer le processus.SIGTERM(Signal Terminate, N°15) : La manière “propre” de demander à un processus de s’arrêter. C’est le signal envoyé par défaut par la commandekill.SIGKILL(Signal Kill, N°9) : Le signal “ultime”. Il ne peut jamais être intercepté ou ignoré. Le système tue le processus de force. C’est lekill -9.SIGHUP(Signal Hang Up, N°1) : Envoyé quand le terminal est fermé.EXIT: Ce n’est pas un vrai signal, mais un événement spécial de Bash qui se déclenche à la fin du script, quelle qu’en soit la raison (fin normale,exit, ou un signal).
trap : Le piège à signaux
La commande intégrée trap permet à votre script d’exécuter du code lorsqu’un ou plusieurs signaux sont reçus. C’est le mécanisme de gestion d’événements de Bash.
Syntaxe de base : trap 'ma_commande' SIGNAL1 SIGNAL2 ...
Le cas d’usage le plus important de trap est de garantir que les opérations de nettoyage sont toujours exécutées.
Syntaxe / Usages
# Exécute la commande 'echo' quand le script reçoit SIGINT (Ctrl+C)
trap 'echo " - Interruption détectée !"' SIGINT
# Exécute une fonction 'cleanup' à la fin du script (normale ou non)
trap cleanup EXIT
# Fonction de nettoyage classique
cleanup() {
echo "Nettoyage des ressources..."
rm -f /tmp/mon_fichier_temporaire.txt
}
# Ignorer un signal (en passant une chaîne vide)
trap '' SIGINT # Ctrl+C est maintenant ignoré
# Réinitialiser le comportement par défaut
trap - SIGINT
Exemples
# 1. Intercepter Ctrl+C pour un message personnalisé
trap 'echo -e "\nArrêt demandé. Au revoir."; exit' SIGINT
echo "Le script tourne... Appuyez sur Ctrl+C pour arrêter proprement."
# Une boucle infinie pour maintenir le script en vie
while true; do
sleep 1
done
# 2. Le motif de nettoyage le plus robuste
# Le trap est défini au début du script.
cleanup() {
echo "--- Exécution du nettoyage ---"
# On supprime le fichier temporaire s'il existe
rm -f "$TMP_FILE"
echo "Nettoyage terminé."
}
trap cleanup EXIT
# Le script crée un fichier temporaire
TMP_FILE=$(mktemp)
echo "Fichier temporaire créé : $TMP_FILE"
echo "Le script travaille..."
echo "Simulons une erreur en plein milieu..."
# exit 1 # Décommentez pour voir le trap s'exécuter
sleep 10
echo "Le script se termine normalement."
Lancez ce deuxième script. Vous verrez que cleanup est appelé à la fin. Maintenant, lancez-le à nouveau et faites Ctrl+C pendant le sleep. Vous verrez que cleanup est quand même appelé avant que le script ne se termine.
Bonnes pratiques
- Le
trap cleanup EXITest votre meilleur ami. Définissez une fonction de nettoyage et liez-la au pseudo-signalEXIT. Cela garantit qu’elle sera appelée dans presque toutes les situations, rendant vos scripts beaucoup plus propres et plus sûrs. - Gardez votre fonction de nettoyage simple et idempotente (on peut l’exécuter plusieurs fois sans causer de problème). Par exemple, utilisez
rm -fqui ne produit pas d’erreur si le fichier n’existe pas. - Déclarez vos
trapau début du script pour qu’ils soient actifs le plus tôt possible.
Pièges courants
- Tenter d’intercepter
SIGKILL: C’est impossible.trap '...' SIGKILLsera ignoré.kill -9terminera toujours votre script de force. - Complexité dans la chaîne de
trap: Mettre des commandes longues et complexes directement dans la chaîne dutrap(trap '...beaucoup de code...' EXIT) est une mauvaise pratique. Utilisez toujours une fonction. - Les signaux et les subshells : Un
trapdéfini dans un script principal n’est pas hérité par les subshells (ex: dans un pipeline|).
Exercices
-
Le script poli :
- Écrivez un script qui entre dans une boucle
while trueavec unsleep 1. - Ajoutez un
trapqui, surSIGINT(Ctrl+C), affiche “Non, pas comme ça ! UtilisezCtrl+\pour quitter.” et continue la boucle. - Ajoutez un second
trapqui, surSIGQUIT(Ctrl+\), affiche “Ok, vous insistez. Au revoir.” et quitte le script.
- Écrivez un script qui entre dans une boucle
-
Nettoyage multi-fichiers :
- Créez un script qui crée trois fichiers temporaires différents (
/tmp/file1,/tmp/file2, etc.). - Écrivez une fonction de nettoyage qui tente de supprimer ces trois fichiers.
- Liez cette fonction à
EXITavectrap. - Ajoutez un
sleep 20pour avoir le temps de l’interrompre. - Lancez le script, interrompez-le, et vérifiez que les fichiers temporaires ont bien été supprimés.
- Créez un script qui crée trois fichiers temporaires différents (
-
Désactivation temporaire :
- Dans un script, mettez en place un
trapqui affiche un message surSIGINT. - Au milieu du script, pour une section de code “critique”, désactivez temporairement le
trap(trap - SIGINT), puis réactivez-le après. - Testez en faisant
Ctrl+Cpendant la section critique et en dehors.
- Dans un script, mettez en place un