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 stocke une valeur pour la réutiliser plus loin. En Bash, la règle qui piège tous les débutants tient dans l'espacement : la déclaration se fait sans espace autour du = (nom="alice", jamais nom = "alice"), car avec des espaces Bash croit exécuter une commande nommée nom. À la lecture, on préfixe le nom par $ ou on l'entoure de ${}, cette dernière forme étant obligatoire dès qu'on colle du texte juste après le nom.
#!/bin/bash
nom="alice"nombre=42
echo "Utilisateur : $nom"echo "Valeur : ${nombre}"Utilisateur : aliceValeur : 42Substitution de commande
Section intitulée « Substitution de commande »La substitution de commande capture la sortie standard d'une commande et la place dans une variable. La forme moderne $(...) remplace l'ancienne notation avec des accents graves : elle s'imbrique proprement et se lit sans ambiguïté. C'est le mécanisme qui permet à un script de réagir à l'état réel du système, par exemple la date du jour ou le nombre de comptes présents.
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 »La commande read met le script en pause et attend une saisie au clavier, qu'elle range dans la variable indiquée. C'est utile pour un script interactif, mais gardez en tête qu'un script automatisé (cron, CI) n'a personne pour répondre : réservez read aux outils lancés à la main.
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 »En administration système, la moitié des conditions portent sur des fichiers : le script existe-t-il, le répertoire est-il présent, ai-je le droit d'écrire ici. Ces opérateurs à une lettre renvoient vrai ou faux et s'utilisent tels quels dans [[ ]]. Le plus courant est -f, qui vérifie qu'un fichier ordinaire existe avant de le lire.
| 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 »Les tests de chaînes servent surtout à valider un argument : est-il vide, vaut-il exactement telle valeur. Le piège classique est -z contre -n : -z est vrai quand la chaîne est vide, -n quand elle contient quelque chose. Entourez toujours la variable de guillemets, sinon une variable vide fait disparaître l'opérande et provoque une erreur de syntaxe.
| 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 »Bash distingue nettement comparaison de nombres et comparaison de chaînes. Pour les nombres, on utilise ces opérateurs à deux lettres (-eq, -lt...), pas les signes < ou > qui, eux, comparent alphabétiquement. Écrire [[ "$a" -gt "$b" ]] compare bien 9 et 10 comme des entiers, là où > placerait « 10 » avant « 9 ».
| 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 »La boucle for répète un bloc pour chaque élément d'une liste. Cette liste peut être écrite à la main, produite par un motif de fichiers (/etc/*.conf) ou une plage {1..5}. C'est la forme à privilégier quand vous connaissez d'avance l'ensemble des éléments à traiter.
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 »Là où for parcourt un ensemble connu, while répète tant qu'une condition reste vraie, sans savoir d'avance combien de tours auront lieu. C'est la boucle à choisir pour attendre qu'un service démarre, ou pour consommer une entrée jusqu'à épuisement. Veillez à ce que la condition finisse par devenir fausse, sinon la boucle tourne indéfiniment.
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 »Lire un fichier ligne à ligne est un besoin quotidien : parcourir une liste de serveurs, traiter un journal, appliquer une action par entrée. La combinaison while IFS= read -r ligne est le patron correct pour le faire sans surprise. Sans le IFS=, Bash supprime les espaces de début et de fin ; sans le -r, il interprète les antislashes. Les deux ensemble garantissent que chaque ligne arrive intacte.
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 sous un nom, pour éviter de répéter le même bloc à plusieurs endroits. En Bash, une contrainte vaut d'être connue tout de suite : une fonction doit être déclarée avant la ligne qui l'appelle, car le script est lu de haut en bas. Placez donc vos fonctions en tête de fichier, juste après le shebang.
#!/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 »Voici un script réaliste qui rassemble tout ce qui précède : une fonction d'affichage, la validation du nombre d'arguments, un test de répertoire, une boucle for de comptage et des codes de sortie explicites. Lisez-le comme un modèle à réutiliser : la ligne set -euo pipefail en tête et la validation d'argument au début sont exactement les réflexes attendus sur un script d'administration sérieux.
#!/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 »Lancer tout le script avec bash -x devient vite illisible sur un script long. Les directives set -x et set +x encadrent la seule portion qui vous intéresse : le traçage démarre à la première, s'arrête à la seconde. C'est la méthode à privilégier pour isoler une commande suspecte sans noyer la sortie.
set -x # début du debugmv "$src" "$dst"set +x # fin du debugshellcheck, analyse statique
Section intitulée « shellcheck, analyse statique »shellcheck est un analyseur statique : il lit le script sans l'exécuter et signale erreurs de syntaxe et pièges classiques, à commencer par les variables non quotées. C'est le premier réflexe à adopter avant de lancer un script, et l'outil que les correcteurs d'examen comme les pipelines CI utilisent pour juger la qualité d'un script. Chaque avertissement porte un code (SC2086, etc.) qui renvoie à une explication détaillée en ligne.
# 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 »Les erreurs de scripting débutant se répètent d'un script à l'autre, et la plupart se lisent dès le message d'erreur. Le tableau ci-dessous associe chaque message exact à sa cause la plus fréquente. Deux réflexes couvrent presque tous les cas : vérifier le droit d'exécution et le shebang pour les problèmes de lancement, lancer shellcheck pour les erreurs de syntaxe.
| 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 |
Contrôle de connaissances
Section intitulée « Contrôle de connaissances »Vérifiez que l'essentiel de ce guide est acquis. Les questions portent uniquement sur ce qui vient d'être expliqué ici.
Contrôle de connaissances
Validez vos connaissances avec ce quiz interactif
Informations
- Le chronomètre démarre au clic sur Démarrer
- Questions à choix multiples, vrai/faux et réponses courtes
- Vous pouvez naviguer entre les questions
- Les résultats détaillés sont affichés à la fin
Lance le quiz et démarre le chronomètre
Vérification
(0/0)Profil de compétences
Quoi faire maintenant
Ressources pour progresser
Des indices pour retenter votre chance ?
Nouveau quiz complet avec des questions aléatoires
Retravailler uniquement les questions ratées
Retour à la liste des certifications
À 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.
Pour aller plus loin
Section intitulée « Pour aller plus loin »- Écrire des scripts robustes : set -euo pipefail, validation d'entrées, trap et fichiers temporaires sécurisés.
- Personnaliser Bash : Alias, fonctions permanentes, prompt et fichiers de configuration.
- Planifier avec cron : Automatiser l'exécution de vos scripts à intervalles réguliers.