Script Bash : Guide pratique pour maîtriser les conditions If, Else et Elif

Les structures conditionnelles représentent le cœur logique de tout script Bash efficace. Comprendre comment exploiter les instructions if, else et elif transforme radicalement la capacité à contrôler le flux d’exécution d’un programme, permettant aux scripts de prendre des décisions autonomes en fonction de conditions variables. C’est la différence entre un simple enchaînement de commandes et une véritable automation intelligente, capable d’adapter son comportement à chaque situation rencontrée.

Miniature vidéo YouTube


📋 Fondamentaux des structures conditionnelles en Bash : syntaxe et logique

La structure conditionnelle constitue l’élément fondamental sur lequel repose la programmation décisionnelle. En Bash, cette logique s’articule autour de trois mots-clés essentiels : if, then et fi (terminator de la condition). Cette syntaxe épurée reflète la philosophie Unix : faire plus avec moins, tout en restant explicite.

La forme la plus basique démarre avec le mot-clé if, suivi d’une condition enfermée entre crochets. Cette condition peut être une commande système, une comparaison numérique, une vérification de fichier ou même une évaluation de variable. Une fois la condition énoncée, le mot-clé then annonce le bloc de code à exécuter si cette condition s’avère vraie. Le bloc s’achève par fi, qui inverse simplement le mot « if » pour marquer explicitement la fin de la structure.

Voici la syntaxe élémentaire d’une instruction if en Bash :

if [ condition ]
then
    # Bloc de code exécuté si la condition est vraie
fi

Ce modèle, bien que simple, s’étend facilement pour gérer plusieurs scénarios. Lorsqu’une condition s’avère fausse et qu’aucune action alternative n’est définie, le script poursuit son exécution sans intervenir. Cependant, la plupart des situations exigent une réaction spécifique même en cas d’échec, d’où l’introduction de l’instruction else.

🔄 Extension avec else : gérer deux scénarios distincts

L’instruction else permet de définir un bloc alternatif, exécuté uniquement si la condition initiale du if s’avère fausse. Cette bifurcation binaire suffit à de nombreux cas d’usage : vérifier l’existence d’un fichier et réagir différemment selon qu’il existe ou non, valider qu’une variable respecte un seuil numérique, confirmer qu’un service est actif, etc.

Voici la structure avec else :

if [ condition ]
then
    # Bloc exécuté si la condition est vraie
else
    # Bloc exécuté si la condition est fausse
fi

L’important à retenir : une seule branche s’exécutera. Si la condition est vraie, le bloc then s’exécute et else est entièrement ignoré. Inversement, si la condition est fausse, c’est le bloc else qui s’active tandis que then est contourné.

🎯 Elif : tester plusieurs conditions en cascade

Lorsque plusieurs scénarios doivent être évalués dans une logique séquentielle, elif (contraction de « else if ») intervient. Cette instruction permet de chaîner plusieurs conditions sans recourir à des structures imbriquées complexes, rendant le code plus lisible et plus maintenable.

Voici la syntaxe complète avec elif :

if [ condition1 ]
then
    # Bloc si condition1 est vraie
elif [ condition2 ]
then
    # Bloc si condition2 est vraie
elif [ condition3 ]
then
    # Bloc si condition3 est vraie
else
    # Bloc si aucune condition n'est vraie
fi

La chaîne s’évalue de haut en bas : dès qu’une condition devient vraie, son bloc associé s’exécute et le reste de la structure est ignoré. Cette évaluation court-circuit améliore les performances et prévient les exécutions redondantes. L’instruction else, bien qu’optionnelle, offre une sécurité en gérant le cas où aucune condition précédente n’est satisfaite.

🔢 Opérateurs de comparaison : tester numériquement et textuellement

Bash propose un ensemble d’opérateurs de comparaison spécifiquement conçus pour évaluer des valeurs. Contrairement à certains langages, la syntaxe Bash distingue clairement les comparaisons numériques des comparaisons textuelles, chacune reposant sur des opérateurs différents. Cette distinction prévient les erreurs logiques courantes où une chaîne serait malencontreusement comparée comme nombre.

Pour les comparaisons numériques, Bash emploie des opérateurs abrégés :

  • 🔹 -eq : égal (equal)
  • 🔹 -ne : non égal (not equal)
  • 🔹 -lt : inférieur (less than)
  • 🔹 -le : inférieur ou égal (less than or equal)
  • 🔹 -gt : supérieur (greater than)
  • 🔹 -ge : supérieur ou égal (greater than or equal)

Pour les comparaisons textuelles, d’autres opérateurs interviennent :

  • 🔹 = : chaînes identiques
  • 🔹 != : chaînes différentes
  • 🔹 -z : chaîne vide
  • 🔹 -n : chaîne non vide

Un exemple concret illustre cette distinction. Supposons une variable contenant la valeur « 5 ». Si l’on écrit [ $variable -gt 3 ], Bash interprète cela comme une comparaison numérique et retourne vrai. En revanche, [ $variable = « 5 » ] constitue une comparaison textuelle, et bien qu’elle retourne également vrai dans ce cas, elle s’interprète différemment en interne.

🗂️ Opérateurs de test de fichiers et répertoires

Au-delà des nombres et textes, Bash offre des opérateurs pour tester l’état des fichiers du système. Cette catégorie s’avère indispensable en scripting système, où l’existence ou la nature d’un fichier détermine souvent le comportement du script.

OpérateurSignificationExemple
-eFichier ou répertoire existe 📁[ -e /home/user/file.txt ]
-fFichier régulier existe 📄[ -f /home/user/script.sh ]
-dRépertoire existe 📂[ -d /home/user ]
-rFichier lisible 👁️[ -r /etc/passwd ]
-wFichier modifiable ✏️[ -w /home/user/config ]
-xFichier exécutable ⚙️[ -x /usr/bin/bash ]

Ces opérateurs s’emploient directement sans variable intermédiaire. Par exemple, [ -f « /path/to/file » ] retourne vrai si le chemin spécifié pointe vers un fichier régulier. Cette simplicité syntaxique en fait un outil puissant pour écrire des scripts défensifs, capables de vérifier leurs conditions avant d’agir.

Miniature vidéo YouTube


💡 Exemples pratiques : du concept à l’implémentation

La théorie s’assimile mieux à travers des cas concrets. Voici plusieurs exemples illustrant les structures conditionnelles en action, progressant en complexité pour offrir une compréhension graduée.

🎬 Exemple 1 : vérifier une valeur numérique simple

Imaginons un script de surveillance système qui doit vérifier si l’utilisation du processeur dépasse un seuil critique. Le script lit une variable contenant le pourcentage d’utilisation, puis décide d’afficher un avertissement ou un message rassurant.

#!/bin/bash

# Utilisation CPU simulée
cpu_usage=75

# Évaluer l'utilisation
if [ $cpu_usage -gt 80 ]
then
    echo "⚠️  Alerte CPU critique : utilisation à $cpu_usage%"
else
    echo "✅ CPU normal : utilisation à $cpu_usage%"
fi

Dans ce cas, comme l’utilisation est 75%, elle ne dépasse pas 80, donc le script affiche le message de statut normal. Modifiez la valeur de cpu_usage à 85 pour observer l’affichage de l’alerte.

🎬 Exemple 2 : tester l’existence d’un fichier

Un script d’installation souvent doit déterminer si un fichier de configuration existe déjà avant de créer une version par défaut. Cette vérification prévient les écrasements accidentels.

#!/bin/bash

config_file="/etc/myapp/config.conf"

if [ -f "$config_file" ]
then
    echo "📄 Fichier de configuration trouvé : $config_file"
    echo "Utilisation de la configuration existante..."
else
    echo "⚠️  Configuration introuvable"
    echo "Création d'une configuration par défaut..."
    # mkdir -p /etc/myapp
    # cp default.conf "$config_file"
fi

Notez l’utilisation de guillemets autour de la variable $config_file. Cette pratique, considérée comme une bonne habitude en scripting Bash, prévient les erreurs liées aux espaces dans les chemins.

🎬 Exemple 3 : brancher sur plusieurs conditions avec elif

Un script de gestion de services doit afficher différents messages selon l’état du service. Cette situation illustre parfaitement où elif devient utile.

#!/bin/bash

# Récupérer l'état du service
service_status=$(systemctl is-active apache2)
port_response=$(curl -s -o /dev/null -w "%{http_code}" http://localhost)

if [ "$service_status" = "active" ] && [ "$port_response" = "200" ]
then
    echo "✅ Service opérationnel et réactif"
elif [ "$service_status" = "active" ]
then
    echo "⚠️  Service actif mais pas de réponse HTTP"
elif [ "$service_status" = "inactive" ]
then
    echo "🔴 Service arrêté"
else
    echo "❓ État du service indéterminé"
fi

Ce script évalue successivement trois conditions : d’abord, il vérifie que le service est actif ET que le serveur répond avec un code HTTP 200. Si cette combinaison échoue, il teste si le service est simplement arrêté, puis gère les cas résiduels. Cette chaîne d’évaluation séquentielle rend le diagnostic progressif et exhaustif.

🔗 Combiner des conditions avec les opérateurs logiques

Les scripts réels exigent rarement de vérifier une seule condition. Le plus souvent, plusieurs critères doivent être évalués ensemble ou alternativement. Bash fournit deux opérateurs logiques essentiels : && (ET logique) et || (OU logique).

L’opérateur && (AND) exige que toutes les conditions enchaînées soient vraies. Si l’une d’elles échoue, l’ensemble retourne faux et les conditions suivantes ne sont pas évaluées. À l’inverse, l’opérateur || (OR) retourne vrai dès que l’une des conditions est vraie, sans évaluer les suivantes.

Voici un script de vérification de prérequis systèmes, illustrant l’opérateur && :

#!/bin/bash

# Vérifier que l'utilisateur est root ET que Docker est installé
if [ $(id -u) -eq 0 ] && command -v docker &> /dev/null
then
    echo "✅ Prérequis satisfaits : administrateur + Docker présent"
    docker --version
else
    echo "❌ Prérequis manquants"
    [ $(id -u) -ne 0 ] && echo "  - Pas d'accès root"
    ! command -v docker &> /dev/null && echo "  - Docker non installé"
fi

Ce script s’exécute différemment selon que les deux conditions sont satisfaites. Un administrateur sans Docker verra le bloc else s’exécuter. Un utilisateur standard avec Docker installé également. Seul le cas où les deux conditions sont vraies affiche le message de succès.

⚡ Combiner ET et OU dans une même expression

Les scénarios complexes exigent souvent de combiner && et ||. L’ordre d’évaluation suit une logique de priorité : les expressions entre parenthèses s’évaluent d’abord, puis la logique s’applique de gauche à droite.

#!/bin/bash

# Vérifier si le système est prêt pour une mise à jour
disk_free=50  # GB libres
mem_available=4  # GB disponibles
is_root=true

if ([ $disk_free -gt 30 ] && [ $mem_available -gt 2 ]) || [ $is_root = true ]
then
    echo "✅ Mise à jour possible"
else
    echo "❌ Ressources insuffisantes pour mettre à jour"
fi

Dans ce script, l’expression vérifie soit que l’espace disque ET la mémoire sont suffisants, soit que l’utilisateur a les droits root. Les parenthèses délimitent clairement le premier groupe logique, rendant l’intention explicite et lisible.

Script Bash : Guide pratique pour maîtriser les conditions If, Else et Elif

🛡️ Bonnes pratiques et pièges courants à éviter

L’écriture de structures conditionnelles robustes exige de connaître les pièges qui attendent les développeurs inexpérimentés. Ces erreurs, souvent subtiles, produisent des comportements imprévisibles ou des faux silencieux.

🔍 L’oubli des guillemets autour des variables

Un classique en scripting Bash : omettre les guillemets autour des variables, particulièrement dans les conditions. Si une variable contient un espace ou reste vide, le script peut se comporter de façon inattendue.

#!/bin/bash

# ❌ Dangereux : pas de guillemets
username=$1  # Passé en argument, peut contenir des espaces
if [ $username = "admin" ]
then
    echo "Accès administrateur"
fi

# ✅ Correct : avec guillemets
if [ "$username" = "admin" ]
then
    echo "Accès administrateur"
fi

Si l’utilisateur passe « super user » comme argument, la première version échouerait avec une erreur de syntaxe. La deuxième gère correctement les espaces grâce aux guillemets.

⚙️ Confusion entre = et ==

En Bash, l’opérateur de comparaison textuelle est = (unique égal). L’opérateur == fonctionne aussi, mais c’est une extension non-POSIX. Pour la portabilité, préférez toujours l’égal unique.

De plus, l’opérateur == supporte les jokers globaux (*, ?) en Bash moderne, tandis que = les traite littéralement. Cette différence subtile cause des bugs difficiles à diagnoster.

📊 Oublier l’absence de retour logique pour les comparaisons numériques

En Bash, les opérateurs de comparaison numériques (-gt, -lt, -eq, etc.) retournent un code de sortie (0 pour vrai, 1 pour faux), contrairement à d’autres langages qui retournent un booléen. Cela signifie qu’on ne peut pas utiliser directement ces opérateurs en dehors d’un contexte conditionnel sans traiter le code de sortie.

#!/bin/bash

# ❌ Dangereux : utiliser directement sans [ ]
result=$(-gt 5 3)  # Syntaxe invalide

# ✅ Correct : les opérateurs -gt, -lt, -eq dans des conditions
if [ 5 -gt 3 ]
then
    echo "5 est supérieur à 3"
fi

Cette distinction explique pourquoi Bash exige systématiquement les crochets autour des conditions : ils invoquent le test builtin interne qui traite les opérateurs comparatifs.

⏱️ Évaluation court-circuit et ordre des conditions

Lorsqu’on utilise && et ||, Bash évalue les conditions de gauche à droite et s’arrête dès que le résultat est déterminé. Cela signifie qu’une condition à droite peut ne jamais s’exécuter.

#!/bin/bash

# Ordre important pour les performances et les effets secondaires
if [ -f "$file" ] && grep -q "pattern" "$file"
then
    echo "Pattern trouvé dans le fichier"
fi

# Inverse l'ordre : plus lent et inefficace
if grep -q "pattern" "$file" && [ -f "$file" ]
then
    echo "Pattern trouvé dans le fichier"
fi

Le premier cas teste d’abord l’existence du fichier (rapide) avant de chercher un motif (lent). Le second ordre inverse serait inefficace, puisque grep chercherait dans un fichier qui pourrait ne pas exister. Organisez vos conditions du test le plus léger au plus coûteux.

🎯 Cas d’usage avancés : scripts réels et contextes professionnels

Au-delà des exemples introductifs, l’application des conditions conditionnelles dans des scénarios professionnels exige une compréhension nuancée de leur interaction avec d’autres outils Bash. Ces cas réels illustrent comment les concepts fondamentaux se composent pour résoudre des problèmes complexes.

📦 Script de gestion de déploiement avec validation progressive

Un script d’administration système doit souvent vérifier une série de conditions avant de procéder à une action critique comme un déploiement. Cette progression de vérifications constitue une garde-fou contre les erreurs.

#!/bin/bash

DEPLOY_USER="deploy"
REPO_PATH="/var/www/app"
BUILD_DIR="./build"
SERVICE_NAME="webapp"

# Étape 1 : Vérifier les permissions
if [ ! -w "$REPO_PATH" ]
then
    echo "❌ Erreur : pas d'accès en écriture à $REPO_PATH"
    exit 1
fi

# Étape 2 : Vérifier les dépendances de build
if [ ! -d "$BUILD_DIR" ]
then
    echo "⚠️  Répertoire build absent, création..."
    mkdir -p "$BUILD_DIR"
fi

# Étape 3 : Arrêter le service existant
if systemctl is-active --quiet $SERVICE_NAME
then
    echo "🛑 Arrêt du service $SERVICE_NAME..."
    systemctl stop $SERVICE_NAME
    sleep 2
elif systemctl is-enabled --quiet $SERVICE_NAME
then
    echo "ℹ️  Service $SERVICE_NAME inactif mais activé"
else
    echo "ℹ️  Service $SERVICE_NAME non trouvé"
fi

# Étape 4 : Déploiement
echo "📦 Déploiement en cours..."
# rsync -av source/ "$REPO_PATH/"

# Étape 5 : Démarrer le service
if systemctl start $SERVICE_NAME
then
    echo "✅ Service $SERVICE_NAME démarré avec succès"
else
    echo "❌ Erreur au démarrage de $SERVICE_NAME"
    exit 1
fi

Ce script progresse par étapes, chacune vérifiant une condition avant de poursuivre. Si l’une des conditions critiques échoue (comme l’absence de permissions), le script s’arrête immédiatement via exit 1, prévenant des modifications partielles ou corrompues.

🔐 Script de validation de sécurité pour fichiers sensibles

Dans un contexte de sécurité système, les scripts doivent valider les attributs des fichiers avant de les traiter. Les permissions incorrectes ou les propriétaires non attendus peuvent signaler des tentatives de compromission.

#!/bin/bash

SECURE_FILE="/etc/shadow"
EXPECTED_OWNER="root"
EXPECTED_PERMS="640"

# Récupérer les métadonnées
file_owner=$(stat -c '%U' "$SECURE_FILE" 2>/dev/null)
file_perms=$(stat -c '%a' "$SECURE_FILE" 2>/dev/null)

# Valider le propriétaire
if [ "$file_owner" != "$EXPECTED_OWNER" ]
then
    echo "🚨 Alerte sécurité : propriétaire incorrect de $SECURE_FILE"
    echo "   Attendu : $EXPECTED_OWNER, Trouvé : $file_owner"
fi

# Valider les permissions
if [ "$file_perms" != "$EXPECTED_PERMS" ]
then
    echo "🚨 Alerte sécurité : permissions incorrectes de $SECURE_FILE"
    echo "   Attendu : $EXPECTED_PERMS, Trouvé : $file_perms"
fi

# Succès global
if [ "$file_owner" = "$EXPECTED_OWNER" ] && [ "$file_perms" = "$EXPECTED_PERMS" ]
then
    echo "✅ Fichier sensible $SECURE_FILE conforme aux normes"
fi

Ce script illustre comment les conditions permettent de valider des aspects critiques de la sécurité système. Les administrateurs peuvent l’intégrer dans des processus de contrôle ou des alertes automatisées.

🔄 Pipeline conditionnel avec exit codes

Un enjeu majeur en scripting Bash professionnel concerne le traitement des codes de sortie (exit codes). Chaque commande retourne un code numérique : 0 indique le succès, toute autre valeur signale une erreur. Les structures conditionnelles se fondent sur cette convention.

#!/bin/bash

# Pipeline : exécuter plusieurs commandes en cascade
echo "🔄 Mise à jour du système..."

# Mise à jour des listes de paquets
apt-get update
if [ $? -ne 0 ]
then
    echo "❌ Erreur lors de la mise à jour des listes"
    exit 1
fi

# Mise à niveau des paquets
apt-get upgrade -y
if [ $? -ne 0 ]
then
    echo "❌ Erreur lors de la mise à niveau des paquets"
    exit 1
fi

# Nettoyage
apt-get autoclean
if [ $? -ne 0 ]
then
    echo "⚠️  Avertissement : nettoyage incomplet"
    # On ne quitte pas ici, car ce n'est pas critique
fi

echo "✅ Mise à jour du système réussie"

La variable spéciale $? contient le code de sortie de la dernière commande exécutée. Cette technique permet d’établir un flux d’exécution conditionnel robuste, où chaque étape dépend du succès de la précédente.

Maîtriser les structures conditionnelles if, else et elif transcende la syntaxe brute ; c’est développer une capacité à articler la logique décisionnelle d’un système. Ces mécanismes, bien qu’apparemment simples, constituent les fondations sur lesquelles reposent les scripts bash robustes et efficaces, capables de naviguer la complexité des environnements informatiques modernes avec fiabilité et prévisibilité.

Retour en haut