0Pricing
Linux Command Line & Bash Scripting Mastery · Leçon

Gestionnaires trap pour le nettoyage et les signaux

Enregistrez des traps EXIT, ERR et INT pour supprimer les fichiers temporaires et annuler de manière fiable les opérations partielles.

Gestionnaires trap pour le nettoyage et les signaux est une leçon Linux Command Line & Bash Scripting Mastery gratuite sur CoddyKit. Ceci est la leçon 2 sur 4. Tu peux lire la leçon complète ci-dessous gratuitement — puis la pratiquer en direct dans le navigateur avec un éditeur de code intégré et un tuteur IA 24/7. Elle fait partie du parcours d'apprentissage Linux Command Line & Bash Scripting Mastery, et ta progression se synchronise sur le web et l'application CoddyKit. Le cours Linux Command Line & Bash Scripting Mastery comprend 4 leçons au total.

Pourquoi les gestionnaires de signaux sont importants

Lorsqu’un script Bash se termine — normalement, à cause d’une erreur ou parce que l’utilisateur a appuyé sur Ctrl+C — il peut laisser des fichiers temporaires, des données partiellement écrites ou un état incohérent. Sans nettoyage, ces éléments s’accumulent et provoquent des problèmes difficiles à diagnostiquer.

Les gestionnaires de signaux résolvent ce problème en enregistrant une fonction ou une commande que Bash exécute automatiquement lorsqu’il reçoit un signal ou un pseudo-signal donné.

  • EXIT — se déclenche chaque fois que le script se termine, quelle qu’en soit la raison
  • ERR — se déclenche après qu’une commande a renvoyé un statut de sortie différent de zéro
  • INT — se déclenche lorsque l’utilisateur envoie SIGINT (Ctrl+C)
  • TERM — se déclenche à la réception de SIGTERM (par exemple, depuis kill)

Un script bien écrit enregistre ces gestionnaires tout en haut, avant le début de toute opération risquée.

Syntaxe de la commande intégrée de gestion des signaux

La commande intégrée trap enregistre un gestionnaire pour un ou plusieurs signaux ou pseudo-signaux. La syntaxe générale est la suivante :

trap 'command_or_function' SIGNAL [SIGNAL...]

Règles essentielles :

  • Le premier argument est une chaîne entre guillemets contenant du code shell (ou un nom de fonction) à exécuter lorsque le signal se déclenche.
  • Vous pouvez énumérer plusieurs signaux après le gestionnaire.
  • trap '' SIGNAL ignore ce signal (gestionnaire vide).
  • trap - SIGNAL rétablit le comportement par défaut du signal.

Les gestionnaires de signaux sont hérités par les fonctions appelées dans le même shell, mais pas par les sous-shells lancés avec ( ) ou &.

#!/usr/bin/env bash
# Syntax examples — not a full script

# Register a cleanup function on EXIT
trap cleanup EXIT

# Inline handler for INT and TERM
trap 'echo "Interrupted!"; exit 1' INT TERM

# Ignore SIGHUP
trap '' HUP

# Reset SIGPIPE to default
trap - PIPE

Le gestionnaire EXIT — votre filet de sécurité

Le pseudo-signal EXIT est le gestionnaire le plus important à enregistrer. Il se déclenche lorsque le shell se termine pour n’importe quelle raison : fin normale, exit N, erreur non gérée ou signal. Il est donc idéal pour supprimer les fichiers temporaires.

Bonne pratique :

  • Créez les fichiers temporaires avec mktemp afin que leur nom soit unique et imprévisible.
  • Stockez immédiatement le chemin dans une variable.
  • Enregistrez le gestionnaire EXIT juste après la création afin que le nettoyage soit toujours exécuté.

Le code de sortie du script est conservé — le code de sortie du gestionnaire est ignoré, sauf si vous appelez explicitement exit à l’intérieur de celui-ci.

#!/usr/bin/env bash
set -euo pipefail

TMPFILE=$(mktemp /tmp/myapp.XXXXXX)

cleanup() {
    echo "Removing temp file: $TMPFILE" >&2
    rm -f "$TMPFILE"
}
trap cleanup EXIT

# Do real work
echo "Processing..." > "$TMPFILE"
sort "$TMPFILE" -o "$TMPFILE"
cp "$TMPFILE" /tmp/myapp_result.txt

echo "Done. Result saved."

Gérer plusieurs fichiers et répertoires temporaires

Les scripts réels créent souvent plusieurs éléments temporaires — fichiers, répertoires, FIFO et fichiers de verrouillage. Au lieu de suivre chacun séparément, regroupez-les dans un tableau et supprimez-les tous dans une seule fonction de nettoyage.

Ce modèle s’adapte facilement : chaque fois que vous créez une nouvelle ressource temporaire, ajoutez-la au tableau. Le gestionnaire EXIT traite toujours la liste complète, quel que soit l’endroit où le script se termine.

#!/usr/bin/env bash
set -euo pipefail

CLEANUP_TARGETS=()

add_cleanup() {
    CLEANUP_TARGETS+=("$1")
}

cleanup() {
    echo "Running cleanup..." >&2
    for target in "${CLEANUP_TARGETS[@]:-}"; do
        rm -rf "$target"
        echo "Removed: $target" >&2
    done
}
trap cleanup EXIT

# Create and track temp resources
TMPDIR_WORK=$(mktemp -d /tmp/work.XXXXXX)
add_cleanup "$TMPDIR_WORK"

TMPFILE_LOG=$(mktemp /tmp/run.XXXXXX.log)
add_cleanup "$TMPFILE_LOG"

echo "Working in $TMPDIR_WORK" | tee "$TMPFILE_LOG"
touch "$TMPDIR_WORK/output.txt"
echo "Step complete."

Le gestionnaire ERR — intercepter les échecs

Le pseudo-signal ERR se déclenche après qu’une commande simple a renvoyé un statut de sortie différent de zéro, à condition que l’option du shell set -e (errexit) soit active ou que la commande ne se trouve pas dans un bloc composé if, while ou ||/&&.

Utilisez le gestionnaire ERR pour :

  • Consigner la ligne qui a échoué avec $LINENO et $BASH_COMMAND.
  • Déclencher la logique d’annulation avant l’exécution du gestionnaire EXIT.
  • Émettre des messages d’erreur structurés vers la sortie d’erreur standard.

Important : les gestionnaires ERR ne se déclenchent pas dans les fonctions, sauf si vous exécutez explicitement set -E (errtrace), afin que les fonctions héritent du gestionnaire ERR du shell appelant.

#!/usr/bin/env bash
set -eEuo pipefail

on_error() {
    local exit_code=$?
    local line=$1
    echo "ERROR: command failed with exit code $exit_code at line $line" >&2
    echo "  Command: $BASH_COMMAND" >&2
}
trap 'on_error $LINENO' ERR

echo "Starting task..."
cp /nonexistent/file /tmp/   # This will fail
echo "This line is never reached."

Le gestionnaire INT — gérer Ctrl+C proprement

Appuyer sur Ctrl+C envoie SIGINT au groupe de processus exécuté au premier plan. Sans gestionnaire, Bash se termine immédiatement et peut laisser derrière lui un travail partiellement effectué.

L’enregistrement d’un gestionnaire INT vous permet de :

  • Afficher un message d’annulation compréhensible pour l’utilisateur.
  • Effectuer toute annulation intermédiaire avant de passer la main au gestionnaire EXIT.
  • Terminer avec un code de statut explicite (130 est le code conventionnel pour SIGINT : 128 + 2).

Une fois votre gestionnaire INT terminé, appelez exit 130 pour transmettre le code de sortie correct. Le gestionnaire EXIT s’exécutera alors automatiquement.

#!/usr/bin/env bash
set -euo pipefail

TMPFILE=$(mktemp /tmp/demo.XXXXXX)

cleanup() {
    rm -f "$TMPFILE"
    echo "Temp file removed." >&2
}

on_interrupt() {
    echo "" >&2
    echo "Caught SIGINT — cancelling gracefully." >&2
    exit 130   # EXIT trap (cleanup) runs automatically after this
}

trap cleanup EXIT
trap on_interrupt INT

echo "Running long task. Press Ctrl+C to cancel."
for i in $(seq 1 10); do
    echo "Step $i/10..."
    sleep 1
done
echo "All steps complete."

Combiner les gestionnaires EXIT, ERR et INT

Dans les scripts destinés à la production, vous enregistrez généralement les trois gestionnaires ensemble afin de couvrir tous les chemins de sortie :

  • EXIT — s’exécute toujours ; il gère le nettoyage des fichiers.
  • ERR — consigne la commande défaillante et le numéro de ligne.
  • INT — affiche un message d’annulation et se termine avec le code 130.

Puisque EXIT s’exécute toujours en dernier, votre logique de nettoyage ne doit se trouver qu’à un seul endroit. Les gestionnaires ERR et INT peuvent se concentrer sur la journalisation et la mise à jour de l’état, puis déléguer le nettoyage proprement dit à EXIT en appelant exit.

Utilisez set -eEuo pipefail au début afin que les erreurs dans les fonctions déclenchent également ERR et que pipefail intercepte les échecs à l’intérieur des pipelines.

#!/usr/bin/env bash
set -eEuo pipefail

TMPFILE=$(mktemp /tmp/combined.XXXXXX)
ROLLBACK_NEEDED=false

cleanup() {
    if [[ "$ROLLBACK_NEEDED" == true ]]; then
        echo "Rolling back partial changes..." >&2
    fi
    rm -f "$TMPFILE"
    echo "Cleanup done." >&2
}

on_error() {
    ROLLBACK_NEEDED=true
    echo "ERR at line $1: $BASH_COMMAND" >&2
}

on_interrupt() {
    echo "Interrupted by user." >&2
    exit 130
}

trap cleanup       EXIT
trap 'on_error $LINENO' ERR
trap on_interrupt  INT

echo "hello" > "$TMPFILE"
echo "Script finished successfully."

Réinitialiser et désactiver dynamiquement les gestionnaires

Vous devez parfois modifier un gestionnaire en cours de script — par exemple pour effectuer un nettoyage unique après la fin d’une section critique, afin que les opérations normales suivantes ne déclenchent pas d’annulation inutile.

  • trap - SIGNAL rétablit le comportement par défaut intégré du signal.
  • trap '' SIGNAL ignore complètement le signal (le processus ne peut pas être interrompu par celui-ci).
  • Vous pouvez enregistrer un nouveau gestionnaire à tout moment ; le dernier appel à trap l’emporte.

Un modèle courant consiste à modifier le gestionnaire EXIT une fois qu’une opération risquée a réussi, en remplaçant le gestionnaire d’annulation par un simple gestionnaire de nettoyage.

#!/usr/bin/env bash
set -euo pipefail

TMPFILE=$(mktemp /tmp/staged.XXXXXX)

rollback() {
    echo "ROLLBACK: removing $TMPFILE" >&2
    rm -f "$TMPFILE"
}

cleanup_only() {
    echo "CLEANUP: removing $TMPFILE" >&2
    rm -f "$TMPFILE"
}

# Start with rollback in case something fails during the risky phase
trap rollback EXIT

echo "Performing risky operation..."
echo "critical data" > "$TMPFILE"
# ... imagine more risky steps here ...

# Risky phase succeeded — switch to simple cleanup
trap cleanup_only EXIT

echo "Risky phase done. Now doing safe finalization."
cp "$TMPFILE" /tmp/staged_result.txt
echo "All done."

Transmettre les codes de sortie à travers les gestionnaires

Un piège subtil : si votre fonction de nettoyage contient des commandes susceptibles d’échouer, le code de sortie final du script peut être remplacé. Conservez explicitement le code de sortie d’origine.

Dans un gestionnaire de signaux, $? contient le code de sortie qui a déclenché le gestionnaire. Capturez-le à la toute première ligne du gestionnaire, avant que toute autre commande ne le modifie.

#!/usr/bin/env bash
set -euo pipefail

TMPFILE=$(mktemp /tmp/exitcode.XXXXXX)

cleanup() {
    local original_exit=$?   # capture BEFORE any other command
    echo "Cleaning up (original exit: $original_exit)" >&2
    rm -f "$TMPFILE"
    # Exit with the original code so callers see the real result
    exit "$original_exit"
}
trap cleanup EXIT

echo "Doing work..."
echo "data" > "$TMPFILE"

# Simulate failure
if [[ ! -f /tmp/required_marker ]]; then
    echo "Required marker missing!" >&2
    exit 2
fi

echo "Done."

Gestionnaires dans les fonctions et les sous-shells

Comprendre l’héritage des gestionnaires est essentiel pour écrire des scripts corrects :

  • Les fonctions s’exécutent dans le même shell et héritent des gestionnaires — mais ERR ne se propage aux fonctions que lorsque set -E (errtrace) est actif.
  • Les sous-shells (( ... )) démarrent avec une copie des gestionnaires du shell parent, mais les changements effectués dans le sous-shell n’affectent pas le parent.
  • Les tâches en arrière-plan (cmd &) sont des sous-shells et n’héritent pas des gestionnaires INT/TERM du parent (elles utilisent le comportement par défaut des signaux).

Règle pratique : conservez l’enregistrement des gestionnaires dans le corps principal du script, utilisez set -E lorsque vous devez propager ERR aux fonctions et ne comptez jamais sur l’héritage des gestionnaires à travers &.

#!/usr/bin/env bash
set -eEuo pipefail   # -E = errtrace: ERR propagates into functions

on_error() {
    echo "ERR in function or main at line $1" >&2
}
trap 'on_error $LINENO' ERR

risky_function() {
    echo "Inside risky_function"
    ls /nonexistent_path   # triggers ERR — works because of set -E
}

# Subshell: has its own copy; changes don't affect parent
(
    trap '' ERR   # disable ERR only inside subshell
    ls /nonexistent_path 2>/dev/null || true
    echo "Subshell completed without triggering parent ERR"
)

risky_function

Modèle concret : remplacement atomique d’un fichier

Un modèle Bash défensif classique est le remplacement atomique d’un fichier : écrivez dans un fichier temporaire, puis renommez-le pour le mettre en place. Si une erreur survient avant le renommage, l’original reste intact. Les gestionnaires rendent cette méthode particulièrement fiable.

Étapes :

  1. Créez un fichier temporaire sur le même système de fichiers que la destination (afin que mv soit atomique).
  2. Enregistrez un gestionnaire EXIT pour supprimer le fichier temporaire en cas d’arrêt prématuré.
  3. Écrivez et validez le nouveau contenu.
  4. Effectuez le renommage atomique (mv) — ce n’est qu’à ce moment que l’original est remplacé.
  5. Le gestionnaire EXIT ne supprime le fichier temporaire que s’il existe encore (après un mv réussi, il n’existe plus).
#!/usr/bin/env bash
set -euo pipefail

DEST="/tmp/important_config.conf"
TMPFILE=$(mktemp "$(dirname "$DEST")/.tmp.XXXXXX")

cleanup() {
    rm -f "$TMPFILE"   # no-op if mv already moved it
}
trap cleanup EXIT

# Write new content to temp file
cat > "$TMPFILE" <<'EOF'
[settings]
version=2
mode=production
EOF

# Validate before replacing
if ! grep -q 'version=' "$TMPFILE"; then
    echo "Validation failed — aborting replacement" >&2
    exit 1
fi

# Atomic rename — DEST is replaced only here
mv "$TMPFILE" "$DEST"
echo "Config updated atomically: $DEST"

Vérification des connaissances : héritage du gestionnaire ERR

Vérifiez votre compréhension du comportement du gestionnaire ERR avec les fonctions dans Bash.

Récapitulatif : gestionnaires pour le nettoyage et les signaux

Dans cette leçon, vous avez appris à rendre les scripts Bash plus robustes grâce aux gestionnaires de signaux :

  • EXIT est votre filet de sécurité universel — enregistrez-le immédiatement après la création de toute ressource temporaire et capturez toujours $? en premier pour conserver le code de sortie d’origine.
  • ERR vous permet de consigner les échecs avec $LINENO et $BASH_COMMAND ; utilisez set -E afin que les fonctions en héritent.
  • INT gère proprement Ctrl+C — affichez un message et quittez avec le code 130 pour laisser EXIT effectuer le nettoyage.
  • Regroupez les ressources temporaires dans un tableau et supprimez-les toutes dans une seule fonction de nettoyage.
  • Utilisez trap - SIGNAL pour réinitialiser les signaux et trap '' SIGNAL pour les ignorer dynamiquement.
  • Le modèle de renommage atomique (mktemp → écriture → validation → mv), combiné à un gestionnaire EXIT, garantit que les écritures partielles ne corrompent jamais le fichier de destination.

Associer set -eEuo pipefail à des gestionnaires placés au bon endroit vous fournit une base défensive solide pour tout script Bash destiné à la production.

Questions Fréquemment Posées

La leçon « Gestionnaires trap pour le nettoyage et les signaux » est-elle gratuite ?

Oui — le texte complet de « Gestionnaires trap pour le nettoyage et les signaux » est gratuit à lire ici sur le web. Pour la pratiquer de manière interactive (un éditeur de code intégré et un tuteur IA 24/7) et déverrouiller le reste du cours Linux Command Line & Bash Scripting Mastery, passe à CoddyKit PRO. Le cours Linux Command Line & Bash Scripting Mastery comprend 4 leçons au total.

Qu'est-ce que j'apprendrai dans « Gestionnaires trap pour le nettoyage et les signaux » ?

Enregistrez des traps EXIT, ERR et INT pour supprimer les fichiers temporaires et annuler de manière fiable les opérations partielles. Tu pratiques Linux Command Line & Bash Scripting Mastery avec du code pratique que tu exécutes directement dans le navigateur, et un tuteur IA 24/7 répond à tes questions au fur et à mesure que tu avances dans la leçon.

Dois-je avoir de l'expérience pour commencer Linux Command Line & Bash Scripting Mastery ?

Aucune expérience préalable n'est requise. Linux Command Line & Bash Scripting Mastery sur CoddyKit est structuré pour les débutants jusqu'aux apprenants avancés, donc tu peux commencer ici ou depuis le début et avancer à ton rythme. Ceci est la leçon 2 sur 4.

Combien de temps prend la leçon « Gestionnaires trap pour le nettoyage et les signaux » ?

La plupart des leçons CoddyKit prennent environ 5–10 minutes. Chacune est courte et interactive, tu progresses régulièrement et tu repiques exactement où tu t'es arrêté sur le web et l'app.

Peux-tu écrire et exécuter du code dans cette leçon Linux Command Line & Bash Scripting Mastery ?

Oui. Chaque leçon Linux Command Line & Bash Scripting Mastery inclut un éditeur de code intégré, tu écris et exécutes du vrai code directement dans ton navigateur et tu reçois des retours IA instantanés — aucune configuration locale requise.

Toutes les leçons de ce cours

  1. Mode strict avec set -euo pipefail
  2. Gestionnaires trap pour le nettoyage et les signaux
  3. Fichiers temporaires sûrs et répertoires de verrouillage
  4. Scripts idempotents et logique de nouvelle tentative avec temporisation
← Retour à Linux Command Line & Bash Scripting Mastery