Ce guide rassemble tout pour écrire un script shell Bash, du shebang aux fonctions. Variables, conditions, boucles, arguments, codes de sortie, débogage : chaque notion est expliquée avec un exemple exécutable, puis approfondie dans une page dédiée. C'est le guide de référence de la section scripting — à lire d'un bout à l'autre pour apprendre, ou à consulter section par section.
Ce que vous allez apprendre
Section intitulée « Ce que vous allez apprendre »- Créer et exécuter un script avec shebang et
chmod +x - Utiliser des variables pour stocker et réutiliser des valeurs
- Écrire des conditions
if/then/fiavec[[ ]] - Répéter des actions avec
foretwhile - Organiser le code avec des fonctions
- Gérer les arguments
$1,$#,$@et les codes de retour$? - Déboguer avec
bash -xetshellcheck
Dans quel contexte ?
Section intitulée « Dans quel contexte ? »Un script Bash est utile dès que vous répétez la même séquence de commandes plus d'une ou deux fois :
- vérifier l'espace disque sur dix serveurs et envoyer une alerte si un seuil est dépassé
- créer un utilisateur avec son répertoire home, ses clés SSH et ses permissions en une commande
- générer un rapport quotidien à partir des logs nginx et l'envoyer par e-mail
- valider l'état d'un service avant de lancer un déploiement
- convertir ou renommer un lot de fichiers selon un pattern
En préparation RHCSA, les scripts shell sont au programme de façon explicite : vous devez être capable d'en écrire un à partir de zéro sous contrainte de temps.
Créer et exécuter son premier script
Section intitulée « Créer et exécuter son premier script »La première ligne d'un script indique quel interpréteur l'exécutera. Sans elle, le shell par défaut du système est utilisé — et ce n'est pas forcément Bash.
#!/bin/bash
echo "Bonjour, $USER !"Enregistrez ce fichier sous bonjour.sh, puis rendez-le exécutable :
chmod +x bonjour.sh./bonjour.shBonjour, bob !#!/bin/bash: le shebang — le système lit ce chemin et lance cet interpréteurchmod +x: ajoute le droit d'exécution au propriétaire./: exécute le script depuis le répertoire courant
Variables
Section intitulée « Variables »Une variable se déclare sans espace autour du = et s'utilise avec $ ou ${}.
#!/bin/bash
nom="alice"nombre=42
echo "Utilisateur : $nom"echo "Valeur : ${nombre}"Utilisateur : aliceValeur : 42Substitution de commande
Section intitulée « Substitution de commande »Pour stocker le résultat d'une commande dans une variable, utilisez $() :
date_du_jour=$(date '+%Y-%m-%d')nb_utilisateurs=$(wc -l < /etc/passwd)
echo "Date : $date_du_jour"echo "Comptes : $nb_utilisateurs"Date : 2026-04-10Comptes : 42Lire une entrée utilisateur
Section intitulée « Lire une entrée utilisateur »echo "Entrez votre nom :"read -r prenomecho "Bonjour, $prenom !"-r désactive l'interprétation des backslashes — toujours utiliser read -r.
Variables automatiques utiles
Section intitulée « Variables automatiques utiles »| Variable | Contenu |
|---|---|
$USER | Nom de l'utilisateur courant |
$HOME | Répertoire personnel |
$PWD | Répertoire courant |
$RANDOM | Nombre aléatoire entre 0 et 32767 |
Conditions
Section intitulée « Conditions »La structure if/then/fi exécute un bloc si une condition est vraie. Utilisez [[ ]] (double crochets) — plus sûr et plus lisible que [ ].
#!/bin/bash
fichier="$1"
if [[ -f "$fichier" ]]; then echo "Le fichier existe."else echo "Le fichier est introuvable."fiTests sur les fichiers
Section intitulée « Tests sur les fichiers »| Opérateur | Condition vraie si… |
|---|---|
-f "$f" | $f est un fichier ordinaire |
-d "$f" | $f est un répertoire |
-e "$f" | $f existe (fichier ou répertoire) |
-r "$f" | $f est lisible |
-w "$f" | $f est modifiable |
-x "$f" | $f est exécutable |
Tests sur les chaînes
Section intitulée « Tests sur les chaînes »| Opérateur | Condition vraie si… |
|---|---|
-z "$s" | $s est vide |
-n "$s" | $s n'est pas vide |
"$a" == "$b" | les deux chaînes sont égales |
"$a" != "$b" | les deux chaînes sont différentes |
Tests numériques
Section intitulée « Tests numériques »| Opérateur | Signification |
|---|---|
-eq | égal |
-ne | différent |
-lt | inférieur strict |
-le | inférieur ou égal |
-gt | supérieur strict |
-ge | supérieur ou égal |
score=85
if [[ $score -ge 90 ]]; then echo "Excellent"elif [[ $score -ge 70 ]]; then echo "Bien"else echo "À améliorer"fiBienfor — itérer sur une liste
Section intitulée « for — itérer sur une liste »for service in nginx ssh cron; do echo "Service : $service"doneService : nginxService : sshService : cronSur les fichiers d'un dossier :
for fichier in /etc/*.conf; do echo "Config : $fichier"doneSur une plage numérique :
for i in {1..5}; do echo "Itération $i"donewhile — boucle conditionnelle
Section intitulée « while — boucle conditionnelle »compteur=1
while [[ $compteur -le 3 ]]; do compteur=$((compteur + 1)) echo "Tour $compteur"doneTour 2Tour 3Tour 4Lire un fichier ligne par ligne
Section intitulée « Lire un fichier ligne par ligne »Pattern courant en administration système :
while IFS= read -r ligne; do echo "→ $ligne"done < /etc/hostnameIFS=: désactive le découpage par espaces/tabulations-r: préserve les backslashes
Fonctions
Section intitulée « Fonctions »Une fonction regroupe des instructions réutilisables. Elle se déclare avant d'être appelée.
#!/bin/bash
afficher_entete() { local titre="$1" echo "" echo "=== $titre ==="}
afficher_entete "Rapport système"afficher_entete "Fin"=== Rapport système ===
=== Fin ===local: la variable reste locale à la fonction — indispensable pour éviter les effets de bord$1,$2… : arguments passés à la fonction (indépendants des arguments du script)
Retourner une valeur textuelle
Section intitulée « Retourner une valeur textuelle »Une fonction retourne un code de sortie (0–255), pas une chaîne. Pour retourner du texte, utilisez echo et récupérez avec $() :
nom_complet() { local prenom="$1" local nom="$2" echo "${prenom} ${nom}"}
resultat=$(nom_complet "alice" "martin")echo "Bonjour, $resultat !"Bonjour, alice martin !Arguments du script
Section intitulée « Arguments du script »Quand vous passez des arguments à votre script, ils sont accessibles via des variables spéciales :
| Variable | Contenu |
|---|---|
$0 | Nom du script |
$1, $2… | Premier, deuxième argument |
$# | Nombre total d'arguments |
$@ | Tous les arguments (liste) |
#!/bin/bash
if [[ $# -ne 2 ]]; then echo "Usage: $0 <source> <destination>" >&2 exit 1fi
echo "Script : $0"echo "Source : $1"echo "Dest : $2"echo "Nb args : $#"./copier.sh /etc/hosts /tmp/hosts.bakScript : ./copier.shSource : /etc/hostsDest : /tmp/hosts.bakNb args : 2Codes de sortie
Section intitulée « Codes de sortie »Chaque commande se termine avec un code de sortie : 0 = succès, valeur non nulle = erreur. $? contient le code de la dernière commande exécutée.
ls /etc/passwdecho "Code : $?" # 0 — succès
ls /fichier-inexistant 2>/dev/nullecho "Code : $?" # 2 — erreurDans un script, exit définit le code retourné à l'appelant :
if [[ ! -d "$1" ]]; then echo "Erreur : '$1' n'est pas un répertoire." >&2 exit 1fi
# … traitement …exit 0Exemple complet
Section intitulée « Exemple complet »Ce script illustre tous les concepts : fonctions, argument, condition, boucle for et codes de sortie.
#!/bin/bash# generer-rapport.sh — rapport d'un répertoire# Usage: ./generer-rapport.sh <repertoire>
set -euo pipefail
afficher_entete() { local titre="$1" echo "" echo "=== $titre ==="}
if [[ $# -ne 1 ]]; then echo "Usage: $0 <repertoire>" >&2 exit 1fi
repertoire="$1"
if [[ ! -d "$repertoire" ]]; then echo "Erreur : '$repertoire' n'est pas un répertoire." >&2 exit 1fi
afficher_entete "Rapport — $repertoire"echo "Date : $(date '+%Y-%m-%d %H:%M')"echo "Utilisateur: $USER"echo ""
nb_fichiers=0for entree in "$repertoire"/*; do [[ -f "$entree" ]] && nb_fichiers=$((nb_fichiers + 1))done
echo "Fichiers : $nb_fichiers"exit 0./generer-rapport.sh /etc=== Rapport — /etc ===Date : 2026-04-10 07:44Utilisateur: bob
Fichiers : 158Déboguer un script
Section intitulée « Déboguer un script »bash -x — voir chaque commande avant exécution
Section intitulée « bash -x — voir chaque commande avant exécution »bash -x ./generer-rapport.sh /etcChaque ligne exécutée est préfixée de + avec les variables substituées. C'est le moyen le plus rapide de suivre l'exécution pas à pas.
set -x / set +x dans le script
Section intitulée « set -x / set +x dans le script »Pour n'activer le debug que sur une portion du code :
set -x # début du debugmv "$src" "$dst"set +x # fin du debugshellcheck — analyse statique
Section intitulée « shellcheck — analyse statique »shellcheck détecte les erreurs de syntaxe et les mauvaises pratiques avant d'exécuter le script.
# Debian/Ubuntusudo apt install shellcheck
# RHEL/Fedorasudo dnf install shellcheckshellcheck mon-script.shmon-script.sh:12:8: warning: Double quote to prevent globbing and word splitting. [SC2086]Dépannage
Section intitulée « Dépannage »| Symptôme | Cause probable | Correction |
|---|---|---|
Permission denied à l'exécution | Droit +x absent | chmod +x mon-script.sh |
bad interpreter: No such file or directory | Shebang incorrect ou encodage Windows (CRLF) | Vérifier #!/bin/bash ; convertir avec dos2unix mon-script.sh |
unbound variable | Variable non définie utilisée avec set -u | Initialiser la variable ou utiliser ${VAR:-} |
| Rien ne se passe après lancement | Shebang manquant ou script lancé avec sh | Ajouter #!/bin/bash et lancer avec ./script.sh |
syntax error near unexpected token | fi/done/guillemet manquant | Lancer shellcheck script.sh pour localiser |
À retenir
Section intitulée « À retenir »- Un script commence toujours par
#!/bin/bashet se rend exécutable avecchmod +x. - Les variables se déclarent sans espace autour du
=et s'utilisent entre guillemets :"$var". - Utilisez
[[ ]]pour les tests — plus sûr que[ ]. - Les fonctions déclarent leurs variables internes avec
local. $1,$2,$#,$@donnent accès aux arguments passés au script.exit 0= succès,exit 1= erreur — toujours explicite.bash -xpour déboguer,shellcheckpour détecter les erreurs à l'avance.