Retour au cours

codes sortie erreurs

Objectifs

  • Comprendre ce qu’est un code de sortie et comment vérifier le succès ou l’échec d’une commande avec $?.
  • Écrire des scripts qui s’arrêtent automatiquement en cas d’erreur avec set -e.
  • Gérer correctement les erreurs dans les pipelines avec set -o pipefail.
  • Combiner les options pour écrire des scripts beaucoup plus sûrs avec set -euo pipefail.

Explications détaillées

Notions clés

Le Code de Sortie : $?

Chaque commande que vous exécutez en Bash renvoie un “code de sortie” (ou “exit code”) à la fin de son exécution. C’est un nombre entier qui indique si la commande a réussi ou non.

  • 0 : Succès.
  • Toute autre valeur (de 1 à 255) : Échec.

La variable spéciale $? contient le code de sortie de la dernière commande qui vient de s’exécuter.

set -e : S’arrêter à la première erreur

Par défaut, si une commande dans un script échoue, le script continue son exécution. C’est dangereux, car il peut continuer à opérer dans un état incohérent.

L’option set -e (ou set -o errexit) change ce comportement : le script se terminera immédiatement si une commande simple échoue. C’est un filet de sécurité fondamental.

set -o pipefail : Ne pas masquer les erreurs dans les pipes

Considérez un pipeline : commande1 | commande2 | commande3. Par défaut, le code de sortie de l’ensemble est celui de la dernière commande (commande3). Si commande1 échoue, mais que commande2 et commande3 réussissent, le pipeline est considéré comme un succès. C’est un problème.

set -o pipefail corrige cela : le code de sortie du pipeline sera celui de la dernière commande du pipe à avoir échoué.

set -u : Détecter les variables non définies

L’option set -u (ou set -o nounset) traite l’utilisation d’une variable qui n’a pas été définie comme une erreur, arrêtant le script. Cela permet de détecter les fautes de frappe dans les noms de variables.

Le “mode strict” : set -euo pipefail

Cette ligne est une bonne pratique quasi universelle à placer au début de vos scripts. Elle combine ces trois protections pour un environnement d’exécution plus sûr et prévisible.

set -euo pipefail est un raccourci pour set -e; set -u; set -o pipefail.

Syntaxe / Usages

# Vérifier le code de sortie de la dernière commande
ls /etc/hosts
echo "Code de sortie : $?" # -> 0

ls /un_dossier_bidon
echo "Code de sortie : $?" # -> non-zéro (généralement 1 ou 2)

# Un script qui s'arrête
set -e
echo "Cette ligne s'exécute."
ls /un_dossier_bidon # Le script s'arrête ici
echo "Cette ligne ne s'exécutera jamais."

# Un pipeline qui échoue correctement
set -o pipefail
commande_qui_echoue | grep "test"
echo "Le code de sortie du pipe est : $?" # -> non-zéro

Exemples

#!/usr/bin/env bash
# On active le mode strict dès le début
set -euo pipefail

echo "Démarrage du script..."

# Cette commande va échouer
commande_inconnue

# Le script s'arrête à la ligne précédente à cause de 'set -e',
# donc ce message ne sera jamais affiché.
echo "Script terminé."

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

# Démonstration de pipefail
# 'grep' réussira (il ne trouve rien), mais 'cat' échouera.
# Sans pipefail, le code de sortie serait 0. Avec pipefail, il sera non-nul.
cat /fichier/inexistant | grep "hello"

echo "Cette ligne ne sera pas atteinte."

Bonnes pratiques

  • Commencez tous vos scripts par set -euo pipefail. C’est la manière la plus simple d’améliorer drastiquement la robustesse de vos scripts.
  • Si vous avez une commande qui peut légitimement échouer et que vous ne voulez pas que le script s’arrête, vous pouvez la gérer explicitement :
    • Avec if : if ! ma_commande; then ... fi
    • Avec || : ma_commande || echo "La commande a échoué, mais ce n'est pas grave."
    • En ajoutant || true : commande_optionnelle || true

Pièges courants

  • Ne pas utiliser set -e : Le plus grand piège est de ne pas l’utiliser et d’avoir un script qui continue de s’exécuter après une erreur critique (ex: un cd qui échoue), effectuant des opérations dans le mauvais dossier.
  • Le comportement de set -e dans les conditions : set -e est temporairement désactivé dans les conditions if, while, ou avec les opérateurs && et ||. C’est ce qui permet d’écrire if commande_qui_echoue; then ....

Exercices

  1. Tester set -e :

    • Créez un script test_errexit.sh qui contient set -e.
    • Faites-le exécuter une commande qui réussit (echo "ok"), puis une qui échoue (ls /n-existe-pas), puis une autre qui réussit (echo "fin").
    • Observez que le script s’arrête à la commande qui échoue et n’affiche jamais “fin”.
  2. Tester pipefail :

    • Exécutez la commande false | true. Vérifiez son code de sortie avec echo $?. Il devrait être 0.
    • Maintenant, exécutez set -o pipefail; false | true. Vérifiez à nouveau le code de sortie. Il devrait être 1.
  3. Script robuste :

    • Créez un script backup_safe.sh qui prend un nom de fichier en argument.
    • Utilisez set -euo pipefail.
    • Le script doit vérifier si le fichier existe. S’il n’existe pas, il doit afficher une erreur et s’arrêter.
    • S’il existe, il doit créer une copie de sauvegarde avec l’extension .bak.