Maîtriser if, else et elif dans un script Bash sans casser la logique

Informatique

Maîtriser if, else et elif dans un script Bash sans casser la logique

16 décembre 2025 10 min de lecture Imran Charpentier

Les conditions Bash ne sont pas seulement une syntaxe à mémoriser. Elles décident si un script continue, s’arrête, crée un fichier, relance un service ou choisit une branche de déploiement. Une ligne if mal pensée peut donc transformer une automatisation utile en erreur silencieuse. La bonne approche consiste à comprendre ce que Bash évalue vraiment : non pas une phrase logique abstraite, mais le code de retour d’une commande ou d’une expression. À partir de là, if, else et elif deviennent beaucoup plus simples à utiliser proprement.

En bref
  • ✓En Bash, if exécute une branche si une commande ou une expression retourne un code de succès.
  • ✓else sert à traiter le cas contraire ; elif évite les imbrications quand plusieurs scénarios sont possibles.
  • ✓Pour les scripts modernes, [[ ... ]] est souvent plus lisible que [ ... ] pour les chaînes et les combinaisons logiques.
  • ✓Les comparaisons numériques, textuelles et les tests de fichiers n’utilisent pas les mêmes opérateurs.
  • ✓Une condition fiable se teste avec des valeurs vides, des chemins avec espaces, un fichier absent et un code de retour inattendu.

Comprendre ce que if teste vraiment

En Bash, if exécute une commande, puis regarde son statut de sortie. Par convention Unix, 0 signifie succès et une autre valeur signale un échec ou un état faux. C’est cette règle qui permet de tester aussi bien une comparaison, l’existence d’un fichier ou le résultat d’une commande système.

La forme minimale reste directe. Le bloc situé après then s’exécute uniquement si la condition réussit, puis fi ferme la structure. Le mot fi, inverse de if, évite toute ambiguïté dans les scripts longs.

#!/usr/bin/env bash

if [[ -f "$HOME/.bashrc" ]]; then
  echo "Configuration Bash trouvée"
fi

Ce premier exemple ne compare pas une phrase ; il vérifie que l’expression [[ -f "$HOME/.bashrc" ]] retourne un succès. Cette nuance compte, car elle autorise aussi des tests sur des commandes réelles. Un script peut ainsi vérifier si une sauvegarde a réussi, si un service répond ou si un répertoire est accessible avant d’aller plus loin, sans transformer chaque contrôle en variable intermédiaire.

La règle pratique : une condition Bash doit correspondre à une situation observable. Sinon, elle documente mal le risque.

Validation de script Bash avec terminal flou et checklist de tests
Avant de rendre un script Bash autonome, chaque condition doit vérifier une situation observable : valeur, fichier, commande ou code de retour.

Ajouter else pour traiter l’échec sans laisser le script muet

Un else utile rend l’échec impossible à ignorer. Il transforme le cas anormal en décision visible dans les logs.

else sert à écrire le comportement attendu quand la condition principale est fausse. Ce n’est pas seulement un confort de lecture : dans un script d’exploitation, une branche d’échec explicite évite de continuer comme si tout allait bien, surtout quand le traitement suivant dépend d’un fichier, d’un service ou d’un droit système. Le message doit être assez précis pour guider la correction, pas seulement annoncer “erreur”, et le code de sortie doit rester exploitable.

Pour aller plus loin

Les points clés sur If, else et elseif sans confusion pour permettent de préciser if, else et elseif sans confusion pour écrire des conditions lisibles.

#!/usr/bin/env bash

config="/etc/mon-app/config.conf"

if [[ -r "$config" ]]; then
  echo "Lecture de la configuration"
else
  echo "Configuration absente ou illisible" >&2
  exit 1
fi

Ici, le script ne se contente pas d’afficher un message. Il sort avec exit 1, ce qui permet à un outil d’orchestration, une tâche cron ou un pipeline CI de comprendre que le traitement a échoué. C’est souvent la différence entre un incident visible et un script qui produit une suite de résultats incohérents, notamment quand plusieurs automatisations s’enchaînent sans supervision humaine immédiate.

La branche else doit donc répondre à une vraie question : faut-il arrêter, créer une valeur par défaut, demander une correction ou essayer un autre chemin ? Une bonne condition ne cache pas l’échec ; elle le rend exploitable.

Utiliser elif quand plusieurs scénarios s’excluent

elif évite de transformer une décision simple en escalier d’imbrications. Le script reste lisible de haut en bas.

Il signifie “sinon si” et permet de tester plusieurs conditions dans une seule chaîne. Bash lit les branches de haut en bas, puis exécute seulement la première condition vraie. Les branches suivantes sont ignorées, ce qui rend l’ordre des tests aussi important que leur syntaxe.

#!/usr/bin/env bash

usage=82

if (( usage >= 90 )); then
  echo "Alerte critique"
elif (( usage >= 75 )); then
  echo "Surveillance renforcée"
else
  echo "Charge normale"
fi

L’ordre des tests est essentiel. Si le seuil 75 était placé avant le seuil 90, une valeur de 95 entrerait dans la mauvaise branche. Les conditions doivent aller du cas le plus spécifique au cas le plus général, surtout quand elles décrivent des seuils, des états ou des profils de risque.

Cette logique évite aussi le piège des if séparés. Trois blocs if indépendants peuvent tous s’exécuter si leurs conditions sont vraies. Une chaîne if / elif / else, elle, exprime une décision exclusive.

Comparatif

Quelle syntaxe choisir ?

[ ... ]

Compatibilité POSIX

Utile si le script doit rester portable hors Bash strict, mais demande plus de précautions sur les guillemets et les opérateurs.

[[ ... ]]

Bash lisible

Pratique pour les chaînes, les motifs, les tests composés et les expressions plus robustes dans un script Bash assumé.

(( ... ))

Calcul entier

Adapté aux compteurs, seuils numériques et expressions arithmétiques sans multiplier les opérateurs -gt ou -eq.

Choisir entre [ ], [[ ]] et (( ))

Le choix de syntaxe ne relève pas du goût personnel. Il dépend du niveau de portabilité attendu, de la nature du test et de la personne qui relira le script après incident. Les crochets simples [ ... ] correspondent au builtin test et restent utiles, mais ils demandent une syntaxe stricte : espaces autour des crochets, variables citées, opérateurs adaptés. Pour un script Bash assumé, [[ ... ]] rend souvent les conditions plus robustes et plus lisibles.

La différence se voit surtout avec les chaînes, les motifs et les combinaisons logiques. [[ ... ]] accepte mieux les expressions composées et limite certains pièges de découpage. Cela ne dispense pas de penser les cas limites, mais cela réduit le bruit syntaxique.

nom_fichier="rapport final.txt"

if [[ -f "$nom_fichier" && -r "$nom_fichier" ]]; then
  echo "Le fichier peut être lu"
else
  echo "Fichier absent ou non lisible"
fi

Pour les nombres entiers, (( ... )) est souvent plus naturel. Il permet d’écrire des comparaisons arithmétiques avec >, >= ou ==, sans passer par -gt, -ge ou -eq. Le résultat reste le même principe : succès ou échec.

  • Utilisez [[ ... ]] quand le script cible clairement Bash et manipule des chaînes, fichiers ou conditions combinées.
  • Gardez [ ... ] quand la portabilité POSIX est une contrainte réelle, pas une habitude héritée.
  • Préférez (( ... )) pour les compteurs, seuils numériques et expressions arithmétiques simples.

Comparer nombres, chaînes et fichiers sans mélanger les opérateurs

Une erreur fréquente consiste à comparer des nombres comme des chaînes, ou des chaînes comme des nombres. Avec [ ... ], les comparaisons numériques utilisent -eq, -ne, -lt, -le, -gt et -ge. Les chaînes utilisent plutôt =, !=, -z et -n.

Les tests de fichiers forment une autre famille. -f vérifie un fichier régulier, -d un répertoire, -r le droit de lecture, -w l’écriture et -x l’exécution. Ces opérateurs sont la base d’un script défensif, parce qu’ils contrôlent l’environnement avant d’agir.

BesoinTest courantExemple
Nombre supérieur à un seuil(( valeur > seuil ))(( usage > 80 ))
Chaîne vide[[ -z "$nom" ]][[ -z "$env" ]]
Fichier lisible[[ -r "$fichier" ]][[ -r "$config" ]]
Dossier existant[[ -d "$chemin" ]][[ -d "$backup_dir" ]]

Les guillemets restent une habitude saine dès qu’une variable représente une chaîne ou un chemin. Un nom de fichier peut contenir un espace, une variable peut être vide, et une valeur inattendue peut déplacer toute l’analyse. Citer les variables, c’est protéger la forme réelle de l’entrée.

Grille de décision

Les vérifications qui rendent une condition Bash fiable

Une condition n’est pas validée parce qu’elle marche une fois. Elle doit résister aux entrées vides, aux fichiers manquants et aux retours d’erreur.

Décision

Variables citées

La valeur peut-elle contenir un espace ?

Impact décision : Les guillemets évitent les découpages inattendus et les tests ambigus.

Décision

Branche par défaut

Que fait le script si aucun cas ne correspond ?

Impact décision : Un else explicite évite les sorties silencieuses.

Décision

Ordre des tests

Le cas le plus précis est-il évalué d’abord ?

Impact décision : Une branche générale placée trop tôt masque les cas particuliers.

Décision

Code de retour

La commande testée peut-elle échouer autrement ?

Impact décision : Un exit status non anticipé peut déclencher la mauvaise branche.

Décision

Chemins absents

Le fichier ou dossier est-il vérifié avant usage ?

Impact décision : Les opérateurs -f, -d, -r ou -x évitent beaucoup d’échecs en chaîne.

Décision

Cas limites

Le script a-t-il été testé avec zéro, vide et valeur inconnue ?

Impact décision : Les bugs de conditions apparaissent souvent hors du scénario nominal.

Combiner les conditions sans rendre le script illisible

Une condition composée doit rester relisible à froid. Sinon, le bug se cache souvent dans l’ordre des critères lors de la relecture.

Les opérateurs && et || permettent de combiner plusieurs tests. Dans [[ ... ]], ils se lisent naturellement : “si le fichier existe et qu’il est lisible”, “si la variable est vide ou inconnue”, etc. Leur usage devient problématique quand la condition porte trop d’intentions à la fois.

if [[ -f "$archive" && -r "$archive" && "$mode" == "restore" ]]; then
  echo "Restauration possible"
else
  echo "Conditions de restauration non réunies"
fi

Cette condition reste lisible parce qu’elle vérifie trois critères liés. Si vous ajoutez la disponibilité réseau, le rôle utilisateur, un seuil de taille et une option de ligne de commande, il vaut mieux découper. Des variables intermédiaires bien nommées peuvent transformer une condition opaque en contrat de lecture, à condition de rester proches du vocabulaire métier ou exploitation que l’équipe utilise déjà.

archive_ok=false
mode_ok=false

[[ -f "$archive" && -r "$archive" ]] && archive_ok=true
[[ "$mode" == "restore" ]] && mode_ok=true

if [[ "$archive_ok" == true && "$mode_ok" == true ]]; then
  echo "Restauration possible"
fi

Ce style n’est pas nécessaire partout. Il devient utile quand le script doit être relu six mois plus tard, repris par une autre équipe ou exécuté dans un contexte sensible. En production, la lisibilité est une sécurité.

Savoir quand remplacer elif par case

elif est excellent pour des seuils, des validations progressives ou quelques états. Mais quand vous comparez une même variable à de nombreuses valeurs textuelles, case devient souvent plus clair. C’est le cas des commandes start, stop, restart, ou des environnements dev, staging, prod.

commande="$1"

case "$commande" in
  start)
    echo "Démarrage"
    ;;
  stop)
    echo "Arrêt"
    ;;
  restart)
    echo "Redémarrage"
    ;;
  *)
    echo "Commande inconnue" >&2
    exit 2
    ;;
esac

La branche *) joue le rôle du défaut. Elle est importante, car elle traite toutes les valeurs non prévues. Sans elle, un argument mal saisi peut traverser le script sans message utile. Là encore, le but n’est pas d’écrire plus de syntaxe, mais de créer un comportement explicite.

Deux contrôles à placer avant la fin du script

Ces deux réflexes évitent la majorité des conditions fragiles dans les scripts d’exploitation.

Contrôle des entrées d’un script Bash avant automatisation

Valider l’entrée avant l’action

Tester la présence, les droits et la valeur attendue avant de modifier un fichier ou lancer une commande sensible.

Revue de branche par défaut et gestion d’erreur dans un script Bash

Prévoir la valeur inconnue

Un argument inattendu doit produire un message clair et un code de sortie exploitable, pas traverser le script sans bruit.

Ce focus tardif sert de rappel opérationnel. Avant la dernière commande sensible, le script doit savoir refuser une entrée douteuse.

Revue de logique conditionnelle Bash sur tableau blanc flou
Quand les branches se multiplient, la lisibilité compte autant que la syntaxe : l’ordre des tests évite souvent les bugs silencieux.

Tester les conditions comme du code de production

Le scénario nominal ne prouve presque rien. Il confirme le chemin heureux, pas la solidité des branches ni la réaction aux erreurs.

Un script Bash est souvent validé avec le cas idéal : le fichier existe, la variable est remplie, le réseau répond, l’utilisateur a les droits. Ce test ne suffit pas, car les conditions les plus dangereuses échouent rarement dans le chemin heureux. Elles cassent quand un argument manque, quand un chemin contient un espace, quand un droit disparaît ou quand une commande retourne un code inattendu, précisément au moment où l’automatisation devrait protéger l’équipe.

  • Variable vide : vérifier que le script affiche une erreur claire ou choisit une valeur par défaut assumée.
  • Chemin avec espace : confirmer que les guillemets protègent bien les noms de fichiers.
  • Fichier absent : vérifier que la branche d’échec ne continue pas vers une commande dangereuse.
  • Droit insuffisant : tester -r, -w ou -x selon l’action prévue.
  • Argument inconnu : s’assurer qu’un else ou un *) renvoie un message et un code de sortie.

Pour aller plus loin, vous pouvez lancer le script avec bash -n pour détecter certaines erreurs de syntaxe, puis exécuter des scénarios contrôlés dans un répertoire temporaire. Cette méthode évite de tester directement sur un fichier réel ou un service actif. Elle force aussi à écrire des conditions qui décrivent précisément ce qui est autorisé et ce qui doit arrêter le traitement.

Un exemple complet de condition Bash maintenable

Voici un exemple volontairement simple : un script reçoit un chemin de configuration, vérifie qu’il existe, qu’il est lisible, puis choisit un comportement selon l’environnement. Les branches restent courtes, les erreurs sortent explicitement, et les valeurs inconnues sont refusées.

#!/usr/bin/env bash
set -u

config="${1:-}"
env_cible="${2:-dev}"

if [[ -z "$config" ]]; then
  echo "Usage: script.sh chemin_config [dev|staging|prod]" >&2
  exit 2
elif [[ ! -f "$config" ]]; then
  echo "Le fichier de configuration est introuvable" >&2
  exit 1
elif [[ ! -r "$config" ]]; then
  echo "Le fichier de configuration n'est pas lisible" >&2
  exit 1
fi

case "$env_cible" in
  dev|staging)
    echo "Validation standard pour $env_cible"
    ;;
  prod)
    echo "Validation renforcée avant production"
    ;;
  *)
    echo "Environnement inconnu" >&2
    exit 2
    ;;
esac

Ce script illustre une règle simple : les conditions de garde arrivent d’abord, avant le traitement principal. Elles éliminent les entrées invalides, puis la suite peut se concentrer sur le vrai travail. Cette structure réduit les imbrications et rend le chemin nominal plus lisible.

La méthode à retenir pour écrire if, else et elif

Un bon bloc conditionnel Bash répond à trois questions. Que teste-t-on réellement ? Que fait-on si le test réussit ? Que fait-on si le test échoue ? Si plusieurs scénarios existent, elif ordonne les branches, mais il ne doit pas devenir un labyrinthe.

En pratique, privilégiez [[ ... ]] pour les scripts Bash modernes, (( ... )) pour l’arithmétique entière et case quand une même variable peut prendre plusieurs valeurs textuelles. Citez les variables, traitez les branches d’échec, retournez des codes explicites et testez les cas limites. Vos scripts deviendront plus prévisibles, plus simples à relire et beaucoup moins fragiles lors d’une automatisation réelle, sans chercher une sophistication inutile ni masquer l’intention derrière une condition compacte.

Questions fréquentes sur if, else et elif en Bash
Imran Charpentier
À propos de l'auteur Imran Charpentier

CTO de NixSoftware, passionné par l’innovation et le développement logiciel depuis plus de 25 ans. J’accompagne les équipes dans la réalisation de solutions robustes et p…

À lire aussi

À lire ensuite

Imprimantes de codes-barres: Le choix clé pour gagner en efficacité
Informatique

Imprimantes de codes-barres: Le choix clé pour gagner en efficacité

Recherchez-vous un équipement capable de vous aider dans la gestion de votre organisation? Les imprimantes de codes-barres occupent une place importante dans de nombreux secteurs. Elles permettent d'identifier rapidement les produits, colis.

·3 min
Poursuivez avec les guides du site

Poursuivez avec les guides du site

Les guides complètent cet article avec une lecture plus structurée, des cas concrets et les points de vigilance à garder en tête.