Aller au contenu
Administration Linux medium

Conditions et tests Bash : if, [[ ]], case

14 min de lecture

Un script Bash sans conditions s’exécute en ligne droite. Avec if/elif/else et les tests [[ ]], il peut réagir à l’état du système : vérifier qu’un fichier existe avant de le lire, valider un argument avant de l’utiliser, ou choisir une action selon la distribution Linux détectée. C’est la base de tout script d’administration réel.

  • Écrire des blocs if / elif / else pour brancher l’exécution
  • Tester l’existence et les attributs de fichiers avec -f -d -r -x
  • Comparer des chaînes et des nombres avec [[ ]]
  • Combiner des conditions avec &&, || et !
  • Utiliser case pour remplacer les if/elif imbriqués
  • Choisir entre [[ ]], [ ] et (( )) selon le contexte

Les conditions interviennent dans la majorité des scripts d’administration :

  • vérifier qu’un fichier de configuration existe avant de le sourcer
  • valider le nombre d’arguments et afficher un usage si $# -lt 2
  • tester si un paquet est installé avant de l’utiliser
  • brancher le comportement selon la distribution (/etc/os-release)
  • gérer les extensions de fichier dans un script de traitement par lots

En préparation RHCSA, if/elif/else, les tests -f, -d, -z, -n et les opérateurs -eq, -gt, -lt sont explicitement au programme.

La syntaxe de base :

Fenêtre de terminal
if CONDITION; then
# commandes si vrai
elif AUTRE_CONDITION; then
# commandes si vrai (sinon)
else
# commandes par défaut
fi

Exemple avec une note :

Fenêtre de terminal
note=14
if (( note >= 16 )); then
echo "Très bien ($note/20)"
elif (( note >= 12 )); then
echo "Bien ($note/20)"
elif (( note >= 10 )); then
echo "Passable ($note/20)"
else
echo "Insuffisant ($note/20)"
fi
# Bien (14/20)

Pour les cas simples (une seule action), les opérateurs && et || sont plus concis qu’un if complet :

Fenêtre de terminal
[[ -f "/etc/nginx/nginx.conf" ]] && echo "Nginx est configuré"
[[ -d "/opt/myapp" ]] || echo "Répertoire /opt/myapp manquant — installation requise"
  • cmd1 && cmd2 : cmd2 s’exécute uniquement si cmd1 réussit (code 0)
  • cmd1 || cmd2 : cmd2 s’exécute uniquement si cmd1 échoue (code ≠ 0)

[[ ]] est le constructeur de test de Bash (distinct de la commande POSIX [ ]). Il évalue une expression et retourne 0 (vrai) ou 1 (faux).

Fenêtre de terminal
fichier="/etc/passwd"
repertoire="/etc"
[[ -f "$fichier" ]] && echo "$fichier est un fichier"
# /etc/passwd est un fichier
[[ -d "$repertoire" ]] && echo "$repertoire est un répertoire"
# /etc est un répertoire
[[ -e "/tmp/inexistant" ]] || echo "Ce fichier n'existe pas"
# Ce fichier n'existe pas
[[ -r "$fichier" ]] && echo "$fichier est lisible"
# /etc/passwd est lisible
[[ -x "/usr/bin/bash" ]] && echo "/usr/bin/bash est exécutable"
# /usr/bin/bash est exécutable
[[ -s "$fichier" ]] && echo "$fichier est non vide"
# /etc/passwd est non vide

Tableau des tests de fichiers courants :

TestSignification
-eExiste (fichier, répertoire, lien…)
-fFichier ordinaire
-dRépertoire
-LLien symbolique
-rLisible par le processus courant
-wInscriptible
-xExécutable
-sExiste et taille > 0
-OAppartient à l’utilisateur courant
-GAppartient au groupe courant
f1 -nt f2f1 est plus récent que f2
f1 -ot f2f1 est plus vieux que f2
Fenêtre de terminal
ville="Paris"
[[ -z "" ]] && echo "Chaîne vide détectée" # vrai
[[ -n "$ville" ]] && echo "$ville est non vide" # Paris est non vide
[[ "$ville" == "Paris" ]] && echo "Égal à Paris" # vrai
[[ "$ville" != "Lyon" ]] && echo "Différent de Lyon" # vrai
[[ "$ville" == P* ]] && echo "Commence par P (glob)" # vrai
[[ "$ville" =~ ^P[a-z]+$ ]] && echo "Correspond au regex" # vrai
TestSignification
-z "$var"Chaîne vide (ou non définie)
-n "$var"Chaîne non vide
"$a" == "$b"Égalité (les globs * ? sont actifs à droite)
"$a" != "$b"Différent
"$a" < "$b"Ordre lexicographique inférieur
"$a" =~ REGEXCorrespond à l’expression régulière POSIX étendue

Pour comparer des nombres, utilisez les opérateurs -eq, -ne, -lt, -le, -gt, -ge dans [[ ]], ou les opérateurs mathématiques (<, >, ==) dans (( )) :

Fenêtre de terminal
x=42
[[ $x -eq 42 ]] && echo "42 -eq 42 : vrai"
[[ $x -gt 10 ]] && echo "42 -gt 10 : vrai"
[[ $x -lt 100 ]] && echo "42 -lt 100 : vrai"
[[ $x -ne 0 ]] && echo "42 -ne 0 : vrai"
# Équivalent plus lisible avec (( ))
(( x > 10 )) && echo "(( 42 > 10 )) : vrai"
(( x == 42 )) && echo "(( 42 == 42 )) : vrai"
[[ ]](( ))Signification
-eq==Égal
-ne!=Différent
-lt<Strictement inférieur
-le<=Inférieur ou égal
-gt>Strictement supérieur
-ge>=Supérieur ou égal

Combinez plusieurs tests dans un seul [[ ]] :

Fenêtre de terminal
fichier="/etc/passwd"
fichier2="/etc/hosts"
absent="/tmp/inexistant"
# ET logique — les deux conditions doivent être vraies
[[ -f "$fichier" && -r "$fichier" ]] && echo "$fichier : fichier ET lisible"
# /etc/passwd : fichier ET lisible
# OU logique — au moins une condition vraie
[[ -f "$absent" || -f "$fichier2" ]] && echo "Au moins un des deux existe"
# Au moins un des deux existe
# NON — inverse la condition
[[ ! -d "$fichier" ]] && echo "$fichier n'est pas un répertoire"
# /etc/passwd n'est pas un répertoire
OutilUsage recommandéCaractéristiques
[[ ]]Tests sur fichiers, chaînes, regexBash uniquement, pas de word splitting, supporte && || =~
[ ]Scripts POSIX portables (#!/bin/sh)Moins puissant, word splitting actif sur les variables
(( ))Tests et calculs arithmétiquesSyntaxe mathématique, retourne 1 si résultat = 0

Règle pratique : en Bash, utilisez [[ ]] pour les chaînes et fichiers, (( )) pour les nombres.

case est plus lisible que des if/elif imbriqués quand on teste une variable contre plusieurs valeurs :

Fenêtre de terminal
extension="backup.tar.gz"
case "${extension##*.}" in
gz|bz2) echo "Archive compressée" ;;
tar) echo "Archive tar non compressée" ;;
log) echo "Fichier journal" ;;
sh|bash) echo "Script shell" ;;
*) echo "Extension inconnue : ${extension##*.}" ;;
esac
# Archive compressée

Avec ${extension##*.}, on extrait l’extension (dernier . et tout ce qui suit). Voir Variables et paramètres Bash pour les expansions de paramètre.

case supporte aussi les plages de caractères :

Fenêtre de terminal
jour=$(date +%u) # 1=lundi … 7=dimanche
case "$jour" in
[1-5]) echo "Semaine (jour $jour)" ;;
[6-7]) echo "Week-end (jour $jour)" ;;
esac
# Semaine (jour 5)
case EXPRESSION in
MOTIF1)
commandes ;;
MOTIF2|MOTIF3) # OU — plusieurs motifs séparés par |
commandes ;;
*) # motif par défaut (obligatoire pour couvrir tous les cas)
commandes ;;
esac

Un script bien écrit valide ses arguments avant d’agir :

#!/bin/bash
set -euo pipefail
usage() {
echo "Usage : $(basename "$0") SOURCE DEST" >&2
exit 1
}
(( $# == 2 )) || usage
src="$1"
dst="$2"
[[ -f "$src" ]] || { echo "Erreur : '$src' n'existe pas." >&2; exit 1; }
[[ -w "$(dirname "$dst")" ]] || { echo "Erreur : répertoire de destination non accessible." >&2; exit 1; }
mv -- "$src" "$dst"
echo "OK : '$src' → '$dst'"

Ce patron — vérifier le nombre d’arguments, vérifier les fichiers, agir — est la structure standard d’un script RHCSA.

SymptômeCause probableSolution
[: unexpected operator[ ] avec && ou || à l’intérieurUtiliser [[ ]] ou séparer en deux tests avec && externe
Test de fichier échoue sur un lien symbolique-f ne passe pas pour un lien briséUtiliser -L pour les liens, -e pour l’existence générale
=~ avec guillemets autour de la regexLa regex est traitée comme une chaîne littéraleRegex sans guillemets : [[ "$var" =~ ^[0-9]+$ ]]
(( 0 )) stoppe le script avec set -e(( expr )) retourne 1 si résultat = 0Protéger : (( expr )) || true ou utiliser [[ ]]
case ne correspond à rienPas de motif *) par défautToujours ajouter *) ... ;; en dernier motif
  • [[ ]] est la forme moderne à préférer en Bash — supporte &&, ||, =~ et ne fait pas de word splitting.
  • Les tests de fichier les plus courants : -f (fichier), -d (répertoire), -r (lisible), -x (exécutable), -s (non vide).
  • Pour les chaînes : -z (vide), -n (non vide), == (égal), =~ (regex).
  • Pour les nombres : -eq, -ne, -lt, -gt dans [[ ]] ou <, >, == dans (( )).
  • case remplace avantageusement les chaînes if/elif sur une même variable.
  • Valider le nombre d’arguments avec (( $# == N )) || usage est un réflexe RHCSA.

Ce site vous est utile ?

Sachez que moins de 1% des lecteurs soutiennent ce site.

Je maintiens +700 guides gratuits, sans pub ni tracing. Aujourd'hui, ce site ne couvre même pas mes frais d'hébergement, d'électricité, de matériel, de logiciels, mais surtout de cafés.

Un soutien régulier, même symbolique, m'aide à garder ces ressources gratuites et à continuer de produire des guides de qualité. Merci pour votre appui.

Abonnez-vous et suivez mon actualité DevSecOps sur LinkedIn