← Sommaire SkyLinux

Leçon 46 : Signaux, erreurs et gestion d'interruption dans les scripts Bash

Dans cette leçon, tu vas apprendre à rendre tes scripts Bash robustes : intercepter les signaux (Ctrl+C), gérer les erreurs, quitter proprement et nettoyer les fichiers temporaires. Quand un script est interrompu ou échoue, c'est souvent parce qu'il n'a pas été conçu pour gérer ces situations.


1. Qu'est-ce qu'un signal ?

Un **signal** est un message envoyé par le système ou par un utilisateur à un processus en cours d'exécution. C'est une forme de communication entre processus — et entre toi et tes scripts.

Les signaux les plus courants

SignalNuméroSignificationAction par défaut
SIGINT (Ctrl+C)2Interruption par l'utilisateurTermine le processus
SIGTERM15Demande d'arrêt propreTermine le processus
SIGKILL9Arrêt forcéTermine immédiatement (impossible à intercepter)
SIGHUP1Le terminal a été ferméLe processus se termine ou se reconfigure
SIGEXIT0Sortie normale du script

Quand tu tapes Ctrl+C dans un terminal, tu envoies un SIGINT au processus en avant-plan. Par défaut, cela termine le programme. Mais avec trap, tu peux décider ce qui se passe à la place.


2. La commande trap — intercepter les signaux

trap te permet d'exécuter une commande (ou une fonction) quand un signal précis est reçu. C'est indispensable pour nettoyer proprement.

Syntaxe de base

trap 'commande' SIGNAL

trap 'fonction' SIGNAL1 SIGNAL2

Exemple fondamental : nettoyer à la sortie

#!/bin/bash

# Fonction de nettoyage

nettoyer() {

echo "Nettoyage en cours..."

rm -f /tmp/mon-script.lock

rm -f /tmp/mon-script.tmp

echo "Programme terminé proprement."

}

# Intercepter Ctrl+C (SIGINT) et sortie normale (EXIT)

trap nettoyer EXIT INT TERM

echo "Mon script tourne... (Ctrl+C pour arrêter)"

sleep 30

**Ce qui se passe :**

**💡 Bonnes pratiques :** Utilise toujours trap pour supprimer les fichiers temporaires et libérer les ressources (locks, sockets, connexions).


3. Gérer les erreurs avec set -e et set -u

Quitter dès qu'une commande échoue : set -e

Par défaut, Bash continue l'exécution même si une commande échoue. set -e change ce comportement.

#!/bin/bash

set -e # Quitte immédiatement si une commande échoue

echo "Création du dossier..."

mkdir /tmp/mon-projet

cd /tmp/mon-projet

echo "Projet créé."

Si mkdir échoue (droits insuffisants, disque plein), le script s'arrête là.

Quitter sur variable non définie : set -u

#!/bin/bash

set -u

echo "Salutation pour $NOM" # Si $NOM n'existe pas → erreur

Sans set -u, Bash remplace $NOM par une chaîne vide sans protester. Avec set -u, le script s'arrête.

Combinaison recommandée

#!/bin/bash

set -euo pipefail

OptionRôle
-eQuitte sur erreur
-uQuitte sur variable non définie
-o pipefailQuitte si une commande dans un pipe échoue (pas seulement la dernière)

4. Vérifier les codes de retour

Chaque commande retourne un **code de sortie** : 0 = succès, != 0 = erreur.

# Lancer une commande et tester son résultat

mkdir /backup || { echo "Échec de la création du dossier"; exit 1; }

# Ou avec if

if grep -q "error" /var/log/syslog; then

echo "Des erreurs ont été trouvées !"

fi

# Capturer le code de sortie dans une variable

ls /etc/passwd

resultat=$?

echo "Code de sortie de ls : $resultat" # 0 si succès


5. Exemple complet : script robuste de sauvegarde

#!/bin/bash

#

# sauvegarde-robuste.sh — Exemple de script avec gestion de signaux et d'erreurs

#

set -euo pipefail

# Répertoires

SOURCE="/home/david/documents"

DEST="/tmp/backup-$(date +%Y%m%d).tar.gz"

LOCKFILE="/tmp/sauvegarde.lock"

# Fonction de nettoyage

cleanup() {

local exit_code=$?

rm -f "$LOCKFILE"

if [ $exit_code -ne 0 ]; then

echo "Sauvegarde échouée (code: $exit_code)" >&2

fi

exit $exit_code

}

# Intercepter les signaux

trap cleanup EXIT INT TERM

# Vérifier qu'une seule instance tourne

if [ -f "$LOCKFILE" ]; then

echo "Une sauvegarde est déjà en cours. Quittez l'autre instance."

exit 1

fi

# Créer le lockfile

echo $$ > "$LOCKFILE"

# Corps du script

echo "Sauvegarde de $SOURCE vers $DEST..."

tar -czf "$DEST" "$SOURCE" && echo "Sauvegarde terminée : $DEST"

# Supprimer le lockfile avant de quitter (cleanup le fait, mais explicite)

rm -f "$LOCKFILE"

**Points clés de ce script :**


6. Les signaux dans la pratique

Envoyer un signal manuellement

# Voir les signaux disponibles

kill -l

# Envoyer SIGTERM à un processus (demande polie)

kill -15 1234

# Envoyer SIGKILL (forcé)

kill -9 1234

# Envoyer un signal à tous les processus d'un nom

pkill -f "mon-script.sh"

Tester un signal dans un script

#!/bin/bash

trap 'echo "Signal reçu !"' INT

echo "En attente... (Ctrl+C pour tester)"

while true; do

sleep 1

done


7. Récapitulatif des options de set

OptionDescription
set -eQuitte si une commande échoue
set -uQuitte si une variable est indéfinie
set -o pipefailQuitte si une commande dans un pipe échoue
set -xAffiche chaque commande avant de l'exécuter (debug)
set -nLit le script sans exécuter (syntax check only)

Pour le debug, tu peux aussi utiliser bash -x mon-script.sh.


8. Exercice pratique

**Objectif :** Créer un script monitoring.sh qui surveille l'espace disque et qui :

1. Quitte proprement sur Ctrl+C (affiche un message d'au revoir)

2. Supprime son fichier lock à la sortie

3. Utilise set -euo pipefail

4. Vérifie l'espace disque et affiche une alerte si > 80%

#!/bin/bash

# Objectif : créer ce script

# 1. Ajouter set -euo pipefail

# 2. Créer un lockfile /tmp/monitoring.lock

# 3. Écrire une fonction cleanup() qui supprime le lock

# 4. Intercepter EXIT, INT, TERM

# 5. Vérifier l'espace disque : df / | grep -v Filesystem | awk '{print $5}' | tr -d '%'

# 6. Si > 80%, afficher "Alerte : espace disque faible !"

# 7. Boucle infinie avec sleep 10

**Solution indicative :**

#!/bin/bash

set -euo pipefail

LOCKFILE="/tmp/monitoring.lock"

cleanup() {

rm -f "$LOCKFILE"

echo "Script arrêté. Au revoir !"

}

trap cleanup EXIT INT TERM

if [ -f "$LOCKFILE" ]; then

echo "Le script tourne déjà."

exit 1

fi

echo $$ > "$LOCKFILE"

echo " Surveillance disque... (Ctrl+C pour arrêter)"

while true; do

usage=$(df / | tail -1 | awk '{print $5}' | tr -d '%')

if [ "$usage" -gt 80 ]; then

echo " Alerte : espace disque à ${usage}% !"

fi

sleep 10

done


Résumé

ConceptCommande / OutilÀ retenir
Intercepter les signauxtrap 'fonction' SIGNettoyer les ressources à la sortie
Quitter sur erreurset -eUtile pour les scripts critiques
Quitter sur variable manquanteset -uÉvite les bugs silencieux
Pipe échecsset -o pipefailDétecte les erreurs dans les pipes
Code de sortie$?0 = succès, != 0 = erreur
Debugbash -x script.shAffiche chaque commande

Un script qui gère ses signaux et ses erreurs, c'est un script **professionnel**. Même si ton serveur coupe, ton script aura le temps de nettoyer ses fichiers temporaires et de préserver ses données.