Un script qui exécute toujours les mêmes lignes, peu importe la situation, est un script aveugle. Le jour où il copie des fichiers vers un dossier qui n’existe pas, ou lance un déploiement alors que le disque est plein, il fait des dégâts. Ce qui transforme une suite de commandes en véritable outil, c’est la capacité à décider : « si le dossier existe, continue ; sinon, arrête-toi proprement ». C’est tout l’objet de ce tutoriel — donner un cerveau à vos scripts.
Dans le fil rouge de la série, Boubacar a déjà son premier outil. Aujourd’hui il en ajoute un plus sérieux : verif-deploiement.sh, un script de garde qui vérifie qu’on peut déployer sans rien casser — le dossier cible est là, le disque a de la place, le fichier de configuration est présent — et qui refuse de continuer si une condition n’est pas remplie.
🎯 Ce que vous allez apprendre
- Écrire des conditions avec
if,elif,elseet tester fichiers, dossiers et nombres ; - Choisir entre
[ ],[[ ]]et(( ))et comprendre pourquoi[[ ]]est plus sûr ; - Lire et exploiter les codes de sortie (
$?,exit) pour signaler succès ou échec ; - Enchaîner des commandes avec
&&et||, et orienter le script aveccase.
🛠️ Ce que vous allez construire
Un script verif-deploiement.sh qui prend en argument le dossier d’un site client, vérifie trois conditions de sécurité avant déploiement, affiche un diagnostic clair, et renvoie un code de sortie exploitable par d’autres scripts. Si tout est vert, il autorise ; sinon, il bloque avec un message précis.
Prérequis
- Avoir suivi Écrire son premier script Bash (shebang, variables,
chmod +x). - Test express : si vous savez déclarer une variable et capturer la sortie d’une commande avec
$(...), vous êtes prêt. - Bash 4+ (testé sous Bash 5.3). ⏱️ Temps estimé : ~30 minutes.
Étape 1 — La structure if et le premier test
La brique de toute décision en Bash est le if. Sa forme est rigide, et trois détails y font trébucher les débutants : le mot-clé then, les espaces autour des crochets, et le fi qui referme (c’est if écrit à l’envers). Commençons par le test le plus courant : un dossier existe-t-il ?
#!/usr/bin/env bash
dossier="/var/www/boutique-aminata"
if [ -d "$dossier" ]; then
echo "Le dossier existe, on peut continuer."
else
echo "Le dossier est introuvable."
fi
L’opérateur -d répond « vrai » si le chemin est un dossier existant. Remarquez les espaces : [ -d "$dossier" ] avec une espace après [ et avant ]. Sans ces espaces, Bash ne reconnaît pas la commande de test et renvoie une erreur. Et bien sûr, "$dossier" est entre guillemets — réflexe acquis au tutoriel précédent. Lancez le script : selon que le dossier existe ou non sur votre machine, vous verrez l’un des deux messages.
Étape 2 — Les opérateurs de test à connaître
Avant d’aller plus loin, faisons l’inventaire des tests les plus utiles. On les classe en trois familles : fichiers, chaînes de caractères, nombres. Inutile de tout mémoriser ; gardez ce tableau sous la main, les bons réflexes viennent à l’usage.
# Fichiers et dossiers
[ -e chemin ] # le chemin existe (fichier OU dossier)
[ -f chemin ] # c'est un fichier ordinaire
[ -d chemin ] # c'est un dossier
[ -r chemin ] # lisible -w : modifiable -x : exécutable
[ -s chemin ] # existe ET n'est pas vide
# Chaînes de caractères
[ -z "$s" ] # la chaîne est vide
[ -n "$s" ] # la chaîne n'est PAS vide
[ "$a" = "$b" ] # égales [ "$a" != "$b" ] : différentes
# Nombres (jamais =, mais -eq, -lt, etc.)
[ "$x" -eq 5 ] # égal -ne : différent
[ "$x" -lt 5 ] # inférieur -le : inférieur ou égal
[ "$x" -gt 5 ] # supérieur -ge : supérieur ou égal
Le piège classique : comparer des nombres avec = ou <. En Bash, = compare des chaînes, et < dans [ ] n’est pas une comparaison numérique mais une redirection. Pour les nombres, on utilise toujours les opérateurs à lettres : -eq, -lt, -gt… Retenez-le, c’est la source d’erreur n°1 sur les conditions.
Étape 3 — Pourquoi préférer [[ ]]
Bash propose une version améliorée des crochets : les doubles crochets [[ ]]. Ce n’est pas une commande externe comme [ ], mais un mot-clé intégré au langage, et il corrige plusieurs défauts. Avec [[ ]], une variable non protégée ne casse pas le test si elle est vide, on peut écrire && et || à l’intérieur, et on dispose de la comparaison par motif et par expression régulière.
fichier_config="$dossier/config.php"
if [[ -d "$dossier" && -f "$fichier_config" ]]; then
echo "Dossier et configuration présents."
fi
# Comparaison par motif (le * est un joker)
if [[ "$dossier" == /var/www/* ]]; then
echo "Le dossier est bien sous /var/www."
fi
Ici une seule condition combine deux tests avec && (« et »), ce qui serait lourd avec [ ]. Le second exemple montre la comparaison par motif : == /var/www/* vérifie que la chaîne commence par /var/www/. C’est très pratique pour valider un chemin avant d’agir dessus. Règle pratique : utilisez [[ ]] par défaut dans vos scripts Bash ; réservez [ ] aux scripts qui doivent rester compatibles sh pur.
✅ Point d’étape — Vous savez tester un dossier, un fichier, une chaîne et un nombre, et vous savez combiner deux conditions avec
[[ ... && ... ]]. Testez vos conditions avec des valeurs réelles avant de continuer.
Étape 4 — Le calcul arithmétique avec (( ))
Pour comparer ou calculer des nombres, Bash offre une troisième forme, dédiée à l’arithmétique : les doubles parenthèses (( )). À l’intérieur, on écrit les maths normalement, avec >, <, +, -, sans $ devant les variables. C’est plus lisible que les -gt et compagnie dès qu’il y a un vrai calcul.
seuil=10
libre=25
if (( libre > seuil )); then
echo "Espace suffisant ($libre Go > $seuil Go)."
fi
# On peut aussi calculer
total=$(( libre + seuil ))
echo "Total : $total Go"
Dans (( libre > seuil )), on lit « si libre est supérieur à seuil ». Pas de guillemets, pas de $ sur les noms (Bash sait qu’il est en mode arithmétique). Et $(( ... )) renvoie le résultat d’un calcul, qu’on range dans une variable. Attention : Bash ne fait que de l’arithmétique entière — $(( 7 / 2 )) vaut 3, pas 3,5. Pour des décimaux, il faut bc ou awk, qu’on verra plus loin dans la série.
Étape 5 — Codes de sortie : le langage des scripts entre eux
Voici le concept le plus sous-estimé des débutants, et pourtant central. Chaque commande, en se terminant, laisse un code de sortie : un nombre entre 0 et 255. Par convention, 0 signifie « succès » et tout le reste signifie « échec » (avec un code différent selon le type d’erreur). On lit ce code dans la variable spéciale $?, juste après la commande.
ls /tmp > /dev/null 2>&1
echo "Code de sortie : $?" # affiche 0
ls /dossier-bidon > /dev/null 2>&1
echo "Code de sortie : $?" # affiche un nombre non nul (souvent 2)
La partie > /dev/null 2>&1 jette la sortie normale et les erreurs à la poubelle (on ne veut que le code, pas le bavardage). Ce code est ce que teste un if : en réalité, if commande; then exécute la commande et regarde si son code vaut 0. Et c’est avec exit que votre script transmet son propre verdict à celui qui l’a appelé.
if [[ ! -d "$dossier" ]]; then
echo "ERREUR : dossier cible absent." >&2
exit 1
fi
Le ! inverse le test (« si le dossier n’existe PAS »). On écrit le message d’erreur sur la sortie d’erreur avec >&2 (bonne pratique : les erreurs vont sur le canal 2, pas mélangées aux résultats), puis exit 1 arrête le script avec le code 1. Un autre script — ou cron, qu’on verra à la fin de la série — pourra alors détecter l’échec et réagir.
Étape 6 — Enchaîner avec && et ||
Maintenant que les codes de sortie sont clairs, deux opérateurs deviennent évidents. && lance la commande suivante seulement si la précédente a réussi (code 0). || lance la suivante seulement si la précédente a échoué. C’est la version condensée et idiomatique d’un if simple.
mkdir -p ~/atelier/sauvegardes && echo "Dossier prêt."
cd /chemin/douteux || echo "Impossible d'entrer dans le dossier."
La première ligne n’affiche « Dossier prêt » que si mkdir a réussi. La seconde n’affiche le message d’erreur que si cd a échoué. On lit ça naturellement : « fais ceci ET ALORS cela », « fais ceci OU SINON cela ». Utilisé avec parcimonie, c’est élégant ; on évite d’en empiler trop, sous peine d’illisibilité.
Étape 7 — Aiguiller avec case
Quand on doit comparer une même variable à plusieurs valeurs possibles, empiler les if/elif/elif devient lourd. Le case est fait pour ça : il aiguille selon la valeur d’une variable, avec une syntaxe lisible et la comparaison par motif (jokers compris). C’est l’outil idéal pour traiter un argument qui peut prendre quelques formes connues — par exemple un environnement de déploiement.
environnement="$1"
case "$environnement" in
prod|production)
echo "Déploiement en PRODUCTION — prudence." ;;
test|staging)
echo "Déploiement de test." ;;
*)
echo "Environnement inconnu : $environnement" >&2
exit 1 ;;
esac
Chaque branche se termine par ;;, et esac (case à l’envers) referme le bloc. Le motif prod|production accepte plusieurs orthographes via la barre verticale, et * en dernier joue le rôle de « tout le reste » — le cas par défaut, qu’on utilise pour rejeter une valeur invalide. Le case gère aussi les jokers : *.log) attraperait tout nom finissant par .log. Plus lisible qu’une cascade de if dès qu’il y a trois cas ou plus.
Étape 8 — Assembler verif-deploiement.sh
On réunit tout : tests de fichiers, comparaison numérique, codes de sortie, messages d’erreur. Le script reçoit le dossier du site en argument, refuse de tourner sans, puis enchaîne les vérifications. Chaque échec arrête le script avec un code distinct — pratique pour diagnostiquer.
#!/usr/bin/env bash
#
# verif-deploiement.sh — vérifie qu'un déploiement est sûr.
# Usage : ./verif-deploiement.sh /var/www/boutique-aminata
# Boîte à outils Atelier — tutoriel 2.
dossier="${1:?Usage : $0 <dossier-du-site>}"
seuil_go=2 # on exige au moins 2 Go libres
# 1. Le dossier cible existe-t-il ?
if [[ ! -d "$dossier" ]]; then
echo "❌ Dossier introuvable : $dossier" >&2
exit 1
fi
# 2. Le fichier de configuration est-il présent et non vide ?
config="$dossier/config.php"
if [[ ! -s "$config" ]]; then
echo "❌ Configuration absente ou vide : $config" >&2
exit 2
fi
# 3. Reste-t-il assez d'espace disque ?
libre_go=$(df -BG --output=avail "$dossier" | awk 'NR==2 {gsub(/G/,""); print $1}')
if (( libre_go < seuil_go )); then
echo "❌ Disque presque plein : ${libre_go} Go libres (< ${seuil_go} Go)." >&2
exit 3
fi
echo "✅ Tout est vert. Déploiement autorisé sur $dossier (${libre_go} Go libres)."
exit 0
Décortiquons les nouveautés. ${1:?message} est une variante de la valeur par défaut : si l’argument manque, Bash arrête le script en affichant le message — parfait pour rendre un argument obligatoire. La ligne du disque utilise df -BG --output=avail pour n’obtenir que l’espace disponible en gigaoctets, puis awk retire la lettre G avec gsub pour ne garder que le nombre, qu’on compare ensuite avec (( )). Chaque sortie d’erreur a son propre code (1, 2, 3) ; un exit 0 final signale le succès franc.
✅ Point d’étape final — Lancez
./verif-deploiement.sh /tmp(qui existe toujours) : le script doit progresser jusqu’au test de config et échouer en code 2. Lancez-le sans argument : il doit afficher le message d’usage. Vérifiez le code du dernier lancement avececho $?.
🐞 Pièges fréquents
| Symptôme / erreur | Cause probable | Correctif |
|---|---|---|
[: missing `]' ou too many arguments |
Espaces oubliés autour des crochets, ou variable vide non protégée | Mettre des espaces : [ -d "$x" ] ; protéger par des guillemets |
| Comparaison numérique fausse | Usage de = ou < pour des nombres |
Utiliser -eq, -lt, -gt… ou (( )) |
integer expression expected |
Variable contenant du texte là où un nombre est attendu | Vérifier la valeur ; nettoyer avec awk/tr au besoin |
Le if ne se ferme pas |
fi oublié ou then manquant |
Forme complète : if ...; then ...; fi |
| Le script continue malgré une erreur | Aucun exit après le message d’erreur |
Ajouter exit N dans la branche d’échec |
🌍 Adaptation au contexte ouest-africain
Sur les VPS mutualisés bon marché très répandus dans la région, le disque est souvent la ressource la plus serrée : 10 ou 20 Go partagés, vite saturés par les logs et les sauvegardes. Un script de garde comme verif-deploiement.sh, qui refuse de déployer quand l’espace manque, évite la panne classique « le site tombe parce que le disque est plein en plein milieu d’un transfert ». Adaptez le seuil_go à la taille réelle de votre serveur. Et comme tout se teste hors-ligne, vous pouvez peaufiner vos conditions sur votre machine avant de les pousser en production, sans consommer de forfait data.
✅ Récapitulatif
Vos scripts savent maintenant décider. Vous maîtrisez le if/elif/else/fi, les opérateurs de test pour fichiers (-d, -f, -s), chaînes (-z, -n, =) et nombres (-eq, -lt…). Vous savez pourquoi [[ ]] est plus sûr que [ ], quand sortir l’artillerie arithmétique (( )), et surtout vous comprenez les codes de sortie — $?, exit N, &&, || — qui sont le langage par lequel les scripts se parlent. verif-deploiement.sh rejoint la boîte à outils.
🧾 Aide-mémoire
| Élément | Rôle |
|---|---|
if ...; then ...; fi |
Structure de décision |
[[ -d "$d" ]] |
Test fichier/chaîne (forme Bash recommandée) |
(( x > y )) |
Comparaison et calcul arithmétiques |
-eq -ne -lt -le -gt -ge |
Comparaisons numériques dans [ ] |
$? |
Code de sortie de la dernière commande |
exit N |
Termine le script avec le code N (0 = succès) |
cmd1 && cmd2 |
cmd2 seulement si cmd1 réussit |
${1:?message} |
Rend l’argument obligatoire |
💪 À vous de jouer
Ajoutez à verif-deploiement.sh une quatrième vérification : refuser le déploiement si le script est lancé en root (mauvaise pratique pour déployer un site). Indice : la variable $EUID vaut 0 pour root.
Voir une solution
if (( EUID == 0 )); then
echo "❌ Ne déployez pas en root. Utilisez un compte dédié." >&2
exit 4
fi
On place ce bloc tout en haut, après la lecture de l’argument : autant refuser avant de faire le moindre test.
Tutoriels frères
- Écrire son premier script Bash — les bases : shebang, exécution, variables.
- Boucles et traitement de fichiers en Bash — répéter une action sur des lots de fichiers.
Pour aller plus loin
- 🔝 Retour au guide principal : Bash scripting : le guide complet.
- Prochain tutoriel conseillé : Boucles et traitement de fichiers.
- Section « Conditional Constructs » du manuel GNU Bash (source officielle).
FAQ
Q : Quelle différence exacte entre [ ] et [[ ]] ?
R : [ ] est une commande POSIX (un programme historique, aussi nommé test). [[ ]] est un mot-clé propre à Bash : il évite le découpage des mots, gère &&/||/=~ à l’intérieur et la comparaison par motif. En Bash, préférez [[ ]] ; en sh pur, vous n’avez que [ ].
Q : Pourquoi mon test sur une variable vide plante avec [ ] ?
R : Si $x est vide et non protégée, [ -n $x ] devient [ -n ], ce qui change de sens. La parade : guillemets ([ -n "$x" ]) ou, mieux, [[ -n $x ]] qui tolère le cas.
Q : Comment tester plusieurs conditions ?
R : Dans [[ ]], utilisez && (et) et || (ou) : [[ -d "$d" && -w "$d" ]]. Évitez les vieux -a/-o de [ ], sources d’ambiguïté.
Q : Quels codes de sortie utiliser pour mes erreurs ?
R : 0 pour le succès, 1 pour une erreur générale, et des codes 2, 3, 4… pour distinguer les cas. Évitez 126, 127 et 128+ qui ont des significations réservées (commande non exécutable, introuvable, signal).
📚 Ressources et références
- GNU Bash Manual — Bash Conditional Expressions : liste officielle de tous les opérateurs de test.
- ShellCheck : analyseur qui repère justement les guillemets manquants et les comparaisons numériques fautives (version 0.11.0, août 2025).
- Bash pour sysadmin : sauvegardes, monitoring, déploiements — pour voir ces conditions appliquées à de vrais déploiements de production.
Mots-clés : conditions bash, if bash, test bash, double crochets, codes de sortie, exit bash, comparaison numérique bash, verif-deploiement.