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
- Avec
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: uncdqui échoue), effectuant des opérations dans le mauvais dossier. - Le comportement de
set -edans les conditions :set -eest temporairement désactivé dans les conditionsif,while, ou avec les opérateurs&&et||. C’est ce qui permet d’écrireif commande_qui_echoue; then ....
Exercices
-
Tester
set -e:- Créez un script
test_errexit.shqui contientset -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”.
- Créez un script
-
Tester
pipefail:- Exécutez la commande
false | true. Vérifiez son code de sortie avececho $?. Il devrait être0. - Maintenant, exécutez
set -o pipefail; false | true. Vérifiez à nouveau le code de sortie. Il devrait être1.
- Exécutez la commande
-
Script robuste :
- Créez un script
backup_safe.shqui 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.
- Créez un script