Écrire un script fiable : bonnes pratiques
Objectifs de la séance
- Comprendre pourquoi le quoting des variables est une question de sécurité, pas seulement de style
- Utiliser
set -eupour rendre un script plus strict face aux erreurs - Structurer un script selon un plan reconnaissable (en-tête, options, constantes, fonctions, programme principal)
- Distinguer sortie standard et sortie d'erreur, et utiliser des codes de sortie explicites
- Découvrir
shellchecket le mode débogagebash -x - Faire le bilan des 6 séances précédentes de Bash niveau 1
Notions théoriques
Le quoting : la règle numéro 1
Nous avons déjà recommandé, séance après séance, d'entourer vos variables de guillemets doubles. Voici pourquoi c'est réellement important, et pas une simple habitude esthétique.
Imaginez ce script :
rm -rf $dossier/*
Si la variable dossier n'a jamais été définie (faute de frappe dans son nom, argument manquant...), elle est vide. La commande devient alors rm -rf /*, qui tente de supprimer l'intégralité du système de fichiers.
Avec des guillemets, rm -rf "$dossier"/*, une variable vide donne rm -rf "/*" — toujours risqué, mais le comportement reste au moins prévisible et le problème est plus facile à anticiper avec les vérifications vues en séance 4.
Le quoting protège aussi contre les espaces et les caractères spéciaux dans les valeurs de vos variables, comme nous l'avons vu dès la séance 2.
set -e et set -u
Deux options, à placer juste après le shebang, rendent un script bien plus strict :
#!/bin/bash
set -eu
set -e: le script s'arrête immédiatement dès qu'une commande échoue (code de retour différent de 0), au lieu de continuer comme si de rien n'était.set -u: le script s'arrête si vous utilisez une variable qui n'a jamais été définie — cela aurait évité l'exemple catastrophique ci-dessus.
Vous croiserez aussi set -o pipefail, qui améliore la détection d'erreur dans une chaîne de commandes reliées par des tubes (|). Nous l'aborderons au niveau 2, avec les pipelines.
set -e ne remplace pas les vérifications explicites vues en séance 4 : certaines commandes (dans un if, par exemple) ont le droit d'échouer sans arrêter le script, c'est même tout l'intérêt d'un test. set -e est un filet de sécurité pour les échecs inattendus, pas un substitut à une gestion d'erreur réfléchie.
La structure canonique d'un script propre
À ce stade du cours, un bon script d'administration suit un plan reconnaissable :
- Shebang (
#!/bin/bash) - En-tête commentée (rôle, auteur)
set -eu- Constantes
- Fonctions
- Programme principal
exit 0final explicite
Des codes de sortie cohérents
Il est utile d'adopter une convention personnelle, par exemple :
0: tout s'est bien passé1: erreur d'usage (mauvais arguments)2: erreur pendant l'exécution (commande qui a échoué)
Un script appelant un autre script peut ainsi réagir différemment selon le code reçu.
Sortie standard et sortie d'erreur
Toute commande Linux dispose de deux canaux de sortie distincts : la sortie standard (le résultat normal) et la sortie d'erreur (les messages de diagnostic). Rediriger un message vers la sortie d'erreur se fait avec >&2 :
echo "Erreur : dossier introuvable" >&2
Cela permet de séparer, par exemple avec ./script.sh > resultat.txt 2> erreurs.txt, ce qui est un résultat exploitable de ce qui est un message de diagnostic.
Déboguer un script
bash -x script.shexécute le script en affichant chaque commande avant de la lancer, avec les variables déjà remplacées.- À l'intérieur d'un script,
set -xactive ce mode pour la suite, etset +xle désactive — pratique pour n'observer qu'une portion suspecte.
shellcheck
shellcheck est un analyseur qui relit votre script et signale les erreurs fréquentes (variable non quotée, faute de syntaxe, piège classique), un peu comme un correcteur orthographique pour le Bash. Sous Debian :
sudo apt install shellcheck
shellcheck sauvegarde.sh
Prenez l'habitude de lancer shellcheck sur chacun de vos scripts avant de les considérer terminés — c'est un réflexe autant apprécié en entreprise qu'un linter pour un langage de développement classique.
Sécurité et lisibilité
- Ne jamais écrire de mot de passe en clair dans un script (rappel de la séance 3).
- Restreindre les permissions d'un script d'administration sensible avec
chmod 700 script.sh(lecture/écriture/exécution pour le seul propriétaire). - Réfléchir avant d'utiliser
sudoà l'intérieur d'un script : préférez appelersudo ./script.shplutôt que multiplier lessudoà l'intérieur, plus difficile à auditer. - Indenter, nommer ses variables clairement, une action par ligne, et commenter le pourquoi d'un choix plutôt que reformuler ce que la ligne fait déjà.
Exemple pratique
Version « brouillon », sans aucune des bonnes pratiques vues aujourd'hui :
#!/bin/bash
rm -rf $dossier/*.tmp
echo "Nettoyage terminé"
Version corrigée :
#!/bin/bash
# Script : nettoyage.sh
# Rôle : supprimer les fichiers temporaires d'un dossier
set -eu
if [ $# -eq 0 ]; then
echo "Usage : $0 <dossier>" >&2
exit 1
fi
dossier="$1"
if [ ! -d "$dossier" ]; then
echo "Erreur : $dossier n'est pas un dossier valide" >&2
exit 1
fi
rm -f "$dossier"/*.tmp
echo "Nettoyage terminé pour $dossier"
exit 0
Sur la version brouillon, shellcheck nettoyage.sh afficherait des avertissements tels que « dossier is referenced but not assigned » et « Double quote to prevent globbing and word splitting » — exactement les deux problèmes que nous venons de corriger.
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Un script nettoyage.sh volontairement bogué vous est fourni ci-dessous. Vous allez l'auditer et le corriger, point par point.
#!/bin/bash
rm -rf $dossier/*.tmp
echo "Nettoyage terminé"
Étape 1 — Ajouter l'en-tête et set -eu
Shebang, en-tête, set -eu : ces trois premières lignes devraient devenir un réflexe pour tout script d'administration que vous écrivez à partir de maintenant.
Étape 2 — Corriger le quoting de la ligne dangereuse
Une variable non quotée dans une commande de suppression n'est pas qu'une question de style : c'est un risque réel de supprimer les mauvais fichiers, voire tout le système, si la variable est vide ou mal renseignée.
Étape 3 — Vérifier l'argument avant d'agir
Un message d'erreur destiné à l'utilisateur ou à un fichier de log doit partir sur la sortie d'erreur (>&2), pas sur la sortie standard. Cela permet à quiconque appelle votre script de rediriger proprement chaque flux (./script.sh > resultat.txt 2> erreurs.txt).
Étape 4 — Faire passer le script sous shellcheck
Faites de shellcheck une étape systématique avant de considérer un script terminé, exactement comme vous le feriez avec un linter dans un langage de développement.
📌 Une solution
Ce qu'il faut retenir
| Notion | Résumé |
|---|---|
| Shebang | #!/bin/bash en première ligne, + chmod +x pour exécuter avec ./script.sh |
| Variables | nom="valeur" sans espaces, utilisation avec "$nom" |
| Entrées | $1, $#, "$@" pour les arguments ; read -p pour la saisie |
| Conditions | if [ test ]; then … fi, code de retour $?, 0 = succès |
| Boucles | for … in … do … done, while … do … done |
| Fonctions | nom() { … }, local, return = code de retour |
| Fiabilité | set -eu, quoting systématique, shellcheck, exit explicite |
Aperçu de la prochaine séance
Vous savez désormais écrire un script Bash complet, fiable et lisible : shebang, variables, arguments, conditions, boucles, fonctions et bonnes pratiques. La séance suivante, Bash scripting – niveau 2, ira plus loin : le case pour des choix multiples plus lisibles qu'une cascade de if, les tableaux pour manipuler des listes de valeurs, getopts pour des options en ligne de commande professionnelles (-h, --verbose...), le traitement de texte avec grep, cut, sed et awk, la gestion d'erreur avancée, la planification de tâches avec cron, et pour finir, des interfaces console conviviales avec dialog et whiptail (cours 50_InterfacesConviviales).