Aller au contenu
Administration Linux medium

Boucles Bash : for, while, until

11 min de lecture

Les boucles Bash permettent de répéter une action sur chaque élément d’un ensemble. Avec for, vous itérez sur une liste connue — serveurs, fichiers, éléments d’un tableau. Avec while, vous traitez un flux dont la taille n’est pas connue à l’avance — chaque ligne d’un fichier de configuration, chaque entrée d’un find. Ce sont les deux outils les plus utilisés dans les scripts d’administration Linux.

  • Écrire une boucle for sur une liste, un tableau, des globs de fichiers et des plages numériques
  • Utiliser while IFS= read -r pour lire un fichier ligne par ligne sans perdre les espaces
  • Lire la sortie d’une commande dans une boucle while
  • Contrôler l’exécution avec break et continue
  • Choisir entre for, while et until en fonction du contexte

Les boucles interviennent dès qu’une action doit être répétée sur plusieurs éléments :

  • vérifier le statut de dix services et afficher ceux qui sont arrêtés
  • renommer en lot tous les fichiers .log d’un répertoire en .log.bak
  • lire /etc/passwd ligne par ligne pour extraire les utilisateurs avec un UID supérieur à 1000
  • attendre qu’un port soit ouvert avant de continuer un déploiement
  • appliquer un patch à une liste de serveurs passée en arguments

En préparation RHCSA, l’itération sur une liste (for) et la lecture de fichier (while read) sont testées dans les exercices de scripting.

Fenêtre de terminal
for serveur in web01 web02 db01; do
echo "Traitement de $serveur"
done
# Traitement de web01
# Traitement de web02
# Traitement de db01
Fenêtre de terminal
services=("nginx" "postgresql" "redis" "sshd")
for svc in "${services[@]}"; do
echo "Service : $svc"
done
# Service : nginx
# Service : postgresql
# Service : redis
# Service : sshd

for f in /etc/*.conf itère sur les fichiers correspondant au pattern :

Fenêtre de terminal
count=0
for f in /etc/*.conf; do
[[ -f "$f" ]] || continue # ignorer les entrées qui ne sont pas des fichiers
echo "$f ($(wc -l < "$f") lignes)"
count=$((count + 1))
(( count >= 5 )) && break
done
# /etc/adduser.conf (109 lignes)
# /etc/ca-certificates.conf (157 lignes)
# /etc/debconf.conf (83 lignes)
# /etc/deluser.conf (41 lignes)
# /etc/dhcpcd.conf (48 lignes)

Plage numérique avec {debut..fin} et {debut..fin..pas}

Section intitulée « Plage numérique avec {debut..fin} et {debut..fin..pas} »
Fenêtre de terminal
for i in {1..5}; do
printf "%d " "$i"
done
# 1 2 3 4 5
for i in {0..20..5}; do # pas de 5
printf "%d " "$i"
done
# 0 5 10 15 20

Utile pour les index ou compteurs avec logique arithmétique :

Fenêtre de terminal
for (( i=1; i<=5; i++ )); do
printf "%d " "$i"
done
# 1 2 3 4 5
# Compter à rebours
for (( i=10; i>=1; i-- )); do
printf "%d " "$i"
done
# 10 9 8 7 6 5 4 3 2 1
Fenêtre de terminal
for ip in $(cat /etc/hosts | awk '{print $1}' | grep -v '^#'); do
echo "Hôte : $ip"
done

while — répéter tant qu’une condition est vraie

Section intitulée « while — répéter tant qu’une condition est vraie »
Fenêtre de terminal
compteur=1
while (( compteur <= 3 )); do
echo "Itération $compteur"
compteur=$((compteur + 1))
done
# Itération 1
# Itération 2
# Itération 3

C’est le patron canonique pour traiter un fichier texte sans perdre les espaces en début de ligne ni les backslashes :

Fenêtre de terminal
while IFS= read -r ligne; do
echo "$ligne"
done < fichier.txt
# → nginx
# → postgresql
# → redis

Décomposition :

  • IFS= — désactive la séparation par espaces/tabulations pendant read
  • read -r — préserve les backslashes tels quels
  • < fichier.txt — redirige le fichier vers l’entrée standard de la boucle
Fenêtre de terminal
count=0
while IFS=: read -r user _ uid _; do
(( uid < 100 )) || continue
echo "$user (uid=$uid)"
count=$((count + 1))
(( count >= 3 )) && break
done < /etc/passwd
# root (uid=0)
# daemon (uid=1)
# bin (uid=2)

IFS=: indique que les champs sont séparés par : (format de /etc/passwd). _ est une variable muette pour ignorer les champs non utiles.

Avec substitution de processus (pour une commande au lieu d’un fichier) :

Fenêtre de terminal
while IFS= read -r ligne; do
echo "$ligne"
done < <(find /var/log -name "*.log" -newer /etc/passwd)

< <(commande) équivaut à rediriger la sortie de commande dans la boucle, sans créer de sous-shell pour la boucle elle-même — ce qui permet de modifier des variables à l’intérieur.

until — répéter jusqu’à ce qu’une condition soit vraie

Section intitulée « until — répéter jusqu’à ce qu’une condition soit vraie »

until est l’inverse de while : la boucle continue tant que la condition est fausse :

Fenêtre de terminal
n=3
until (( n <= 0 )); do
echo "Compte à rebours : $n"
n=$((n - 1))
done
# Compte à rebours : 3
# Compte à rebours : 2
# Compte à rebours : 1

Cas d’usage typique : attendre qu’un service soit disponible.

Fenêtre de terminal
until nc -z localhost 5432 2>/dev/null; do
echo "PostgreSQL pas encore prêt, nouvelle tentative dans 2s..."
sleep 2
done
echo "PostgreSQL disponible."
  • break : sort de la boucle immédiatement
  • continue : passe à l’itération suivante sans exécuter le reste du corps
Fenêtre de terminal
for i in {1..10}; do
(( i % 2 != 0 )) && continue # ignorer les impairs
(( i > 8 )) && break # s'arrêter à 8
printf "%d " "$i"
done
echo ""
# 2 4 6 8

break N et continue N permettent de sortir ou passer à l’itération d’une boucle externe imbriquée (N = niveau) :

Fenêtre de terminal
for hote in web01 web02; do
for port in 80 443 8080; do
nc -z "$hote" "$port" 2>/dev/null && continue 2 # port ouvert : passer à l'hôte suivant
echo "$hote:$port FERMÉ"
done
done
SituationBoucle recommandée
Liste connue (serveurs, fichiers, arguments)for item in liste
Plage numérique ou compteur simplefor i in {1..N} ou for ((i=0; ...))
Taille inconnue — lire fichier ou commandewhile IFS= read -r
Attendre une condition externeuntil condition
Condition dépend d’un compteur modifiablewhile (( compteur < MAX ))
SymptômeCause probableSolution
Variables modifiées dans le while perdues aprèsBoucle dans un sous-shell via pipeUtiliser while ... done < <(cmd) au lieu de cmd | while
Glob *.conf passe la chaîne littéraleAucun fichier ne correspondVérifer avec [[ -f "$f" ]] || continue
{1..N} avec variable : {1..$n} ne s’expande pasLes accolades s’expandent avant les variablesUtiliser seq "$n" ou for (( i=1; i<=n; i++ ))
for ligne in $(cat fichier) découpe sur les espacesWord splitting actifUtiliser while IFS= read -r ligne; do ... done < fichier
break dans un sous-shell ne sort pas de la boucle principaleBoucle + sous-shell = contextes séparésÉviter les sous-shells dans les boucles critiques
  • for item in "${tableau[@]}" est la forme sûre pour itérer sur un tableau — avec guillemets doubles.
  • while IFS= read -r ligne; do ... done < fichier est le patron canonique pour lire un fichier ligne par ligne.
  • Évitez cmd | while read — le pipe crée un sous-shell, les variables sont perdues après la boucle.
  • break sort de la boucle, continue passe à l’itération suivante — suffixez d’un entier pour les boucles imbriquées.
  • {1..N} ne s’expande pas avec des variables — utilisez seq ou for (( )).

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