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.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Écrire des blocs
if/elif/elsepour 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
casepour remplacer les if/elif imbriqués - Choisir entre
[[ ]],[ ]et(( ))selon le contexte
Dans quel contexte ?
Section intitulée « Dans quel 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.
if / elif / else
Section intitulée « if / elif / else »La syntaxe de base :
if CONDITION; then # commandes si vraielif AUTRE_CONDITION; then # commandes si vrai (sinon)else # commandes par défautfiExemple avec une note :
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)&& et || comme conditions en ligne
Section intitulée « && et || comme conditions en ligne »Pour les cas simples (une seule action), les opérateurs && et || sont plus concis qu’un if complet :
[[ -f "/etc/nginx/nginx.conf" ]] && echo "Nginx est configuré"[[ -d "/opt/myapp" ]] || echo "Répertoire /opt/myapp manquant — installation requise"cmd1 && cmd2:cmd2s’exécute uniquement sicmd1réussit (code 0)cmd1 || cmd2:cmd2s’exécute uniquement sicmd1échoue (code ≠ 0)
Tests avec [[ ]]
Section intitulée « Tests avec [[ ]] »[[ ]] est le constructeur de test de Bash (distinct de la commande POSIX [ ]). Il évalue une expression et retourne 0 (vrai) ou 1 (faux).
Tests sur les fichiers
Section intitulée « Tests sur les fichiers »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 videTableau des tests de fichiers courants :
| Test | Signification |
|---|---|
-e | Existe (fichier, répertoire, lien…) |
-f | Fichier ordinaire |
-d | Répertoire |
-L | Lien symbolique |
-r | Lisible par le processus courant |
-w | Inscriptible |
-x | Exécutable |
-s | Existe et taille > 0 |
-O | Appartient à l’utilisateur courant |
-G | Appartient au groupe courant |
f1 -nt f2 | f1 est plus récent que f2 |
f1 -ot f2 | f1 est plus vieux que f2 |
Tests sur les chaînes
Section intitulée « Tests sur les chaînes »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| Test | Signification |
|---|---|
-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" =~ REGEX | Correspond à l’expression régulière POSIX étendue |
Tests numériques
Section intitulée « Tests numériques »Pour comparer des nombres, utilisez les opérateurs -eq, -ne, -lt, -le, -gt, -ge dans [[ ]], ou les opérateurs mathématiques (<, >, ==) dans (( )) :
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 |
Opérateurs logiques
Section intitulée « Opérateurs logiques »Combinez plusieurs tests dans un seul [[ ]] :
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[[ ]] vs [ ] vs (( ))
Section intitulée « [[ ]] vs [ ] vs (( )) »| Outil | Usage recommandé | Caractéristiques |
|---|---|---|
[[ ]] | Tests sur fichiers, chaînes, regex | Bash uniquement, pas de word splitting, supporte && || =~ |
[ ] | Scripts POSIX portables (#!/bin/sh) | Moins puissant, word splitting actif sur les variables |
(( )) | Tests et calculs arithmétiques | Syntaxe 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 :
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éeAvec ${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 :
jour=$(date +%u) # 1=lundi … 7=dimanchecase "$jour" in [1-5]) echo "Semaine (jour $jour)" ;; [6-7]) echo "Week-end (jour $jour)" ;;esac# Semaine (jour 5)Syntaxe de case
Section intitulée « Syntaxe de case »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 ;;esacVérifier les arguments — patron courant
Section intitulée « Vérifier les arguments — patron courant »Un script bien écrit valide ses arguments avant d’agir :
#!/bin/bashset -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.
Dépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Solution |
|---|---|---|
[: unexpected operator | [ ] avec && ou || à l’intérieur | Utiliser [[ ]] 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 regex | La regex est traitée comme une chaîne littérale | Regex sans guillemets : [[ "$var" =~ ^[0-9]+$ ]] |
(( 0 )) stoppe le script avec set -e | (( expr )) retourne 1 si résultat = 0 | Protéger : (( expr )) || true ou utiliser [[ ]] |
case ne correspond à rien | Pas de motif *) par défaut | Toujours ajouter *) ... ;; en dernier motif |
À retenir
Section intitulée « À retenir »[[ ]]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,-gtdans[[ ]]ou<,>,==dans(( )). caseremplace avantageusement les chaînesif/elifsur une même variable.- Valider le nombre d’arguments avec
(( $# == N )) || usageest un réflexe RHCSA.