Stratégies de boucles puissantes : Itération sur les fichiers et les listes dans les scripts Bash
Les boucles Bash sont le moteur de l'automatisation dans le scripting shell. Que vous ayez besoin de traiter chaque fichier d'un répertoire, d'effectuer une tâche un nombre défini de fois, ou de lire des données de configuration ligne par ligne, les boucles fournissent la structure nécessaire pour gérer efficacement les opérations répétitives.
Maîtriser les deux constructions de boucles Bash principales – for et while – est essentiel pour écrire des scripts robustes, évolutifs et intelligents. Ce guide explore la syntaxe fondamentale, les cas d'utilisation pratiques et les meilleures pratiques pour itérer sur des listes, des fichiers, des répertoires et générer des séquences afin de suralimenter vos flux de travail d'automatisation.
La boucle for : Itération sur des ensembles fixes
La boucle for est idéale lorsque vous connaissez à l'avance la collection d'éléments que vous devez traiter. Cette collection peut être une liste explicite de valeurs, les résultats d'une commande ou un ensemble de fichiers trouvés via le globbing.
1. Itération sur des listes standard
Le cas d'utilisation le plus courant implique l'itération sur une liste d'éléments séparés par des espaces.
Syntaxe
for VARIABLE in LISTE_ELEMENTS; do
# Commandes utilisant $VARIABLE
done
Exemple : Traitement d'une liste d'utilisateurs
# Liste des utilisateurs à traiter
UTILISATEURS="alice bob charlie"
for user in $UTILISATEURS; do
echo "Vérification du répertoire personnel de $user..."
if [ -d "/home/$user" ]; then
echo "$user est actif."
else
echo "Avertissement : répertoire personnel de $user manquant."
fi
done
2. Itération numérique de style C
Pour les tâches qui nécessitent de compter ou des séquences numériques spécifiques, Bash prend en charge une boucle for de style C, souvent combinée à l'expansion d'accolades ou à la commande seq.
Syntaxe (Style C)
for (( INITIALISATION; CONDITION; INCREMENTATION )); do
# Commandes
done
Exemple : Script de compte à rebours
# Boucle 5 fois (i commence à 1, continue tant que i est inférieur ou égal à 5)
for (( i=1; i<=5; i++ )); do
echo "Numéro d'itération : $i"
sleep 1
done
echo "Terminé !"
Alternative : Utilisation de l'expansion d'accolades pour des séquences simples
L'expansion d'accolades est plus simple et plus rapide que l'utilisation de seq pour générer des entiers contigus ou des séquences.
# Génère les nombres de 10 à 1
for num in {10..1}; do
echo "Compte à rebours : $num"
done
3. Itération sur des fichiers et répertoires (Globbing)
L'utilisation de caractères génériques (*) dans la boucle for vous permet de traiter les fichiers qui correspondent à un modèle spécifique, tels que tous les fichiers journaux ou tous les scripts d'un répertoire.
Exemple : Archivage de fichiers journaux
Il est crucial de mettre les guillemets autour de la variable ("$file") lors de la manipulation de noms de fichiers, en particulier ceux contenant des espaces ou des caractères spéciaux.
REPERTOIRE_CIBLE="/var/log/application"
# Boucle sur tous les fichiers se terminant par .log dans le répertoire cible
for logfile in "$REPERTOIRE_CIBLE"/*.log; do
# Vérifie si un fichier existe réellement (évite d'exécuter sur le littéral "*.log" si aucun fichier ne correspond)
if [ -f "$logfile" ]; then
echo "Compression de $logfile..."
gzip "$logfile"
fi
done
La boucle while : Exécution basée sur une condition
La boucle while continue d'exécuter un bloc de commandes tant qu'une condition spécifiée reste vraie. Elle est couramment utilisée pour lire des flux d'entrée, surveiller des conditions ou gérer des tâches dont le nombre d'itérations est inconnu.
1. Boucle while de base
Syntaxe
while CONDITION; do
# Commandes
done
Exemple : Attente d'une ressource
Cette boucle utilise la commande test ([ ]) pour vérifier si un répertoire existe avant de continuer.
CHEMIN_RESSOURCE="/mnt/data/share"
while [ ! -d "$CHEMIN_RESSOURCE" ]; do
echo "Attente du montage de la ressource $CHEMIN_RESSOURCE..."
sleep 5
done
echo "La ressource est disponible. Démarrage de la sauvegarde."
2. Le modèle robuste while read
L'application la plus puissante de la boucle while consiste à lire le contenu d'un fichier ou d'un flux de sortie ligne par ligne. Ce modèle est bien supérieur à l'utilisation d'une boucle for sur la sortie de cat, car il gère de manière fiable les espaces et les caractères spéciaux.
Meilleure pratique : Lecture ligne par ligne
Pour garantir une robustesse maximale, nous utilisons trois composants clés :
1. IFS=: Efface le séparateur de champs interne, garantissant que toute la ligne, y compris les espaces de début/fin, est lue dans la variable.
2. read -r: L'option -r empêche l'interprétation des barres obliques inverses (lecture brute), ce qui est essentiel pour les chemins et les chaînes complexes.
3. Redirection d'entrée (<): Redirige le contenu du fichier dans la boucle, garantissant que la boucle s'exécute dans le contexte shell actuel (évitant les problèmes de sous-shell).
# Fichier contenant des données, un élément par ligne
FICHIER_CONFIG="/etc/app/servers.txt"
while IFS= read -r nom_serveur; do
# Ignore les lignes vides ou commentées
if [[ -z "$nom_serveur" || "$nom_serveur" =~ ^# ]]; then
continue
fi
echo "Pinging du serveur : $nom_serveur"
ping -c 1 "$nom_serveur"
done < "$FICHIER_CONFIG"
Astuce : Éviter
catdans les bouclesN'utilisez jamais
cat fichier | while read ligne; do...lors de la lecture de fichiers. Le piping crée un sous-shell, ce qui signifie que les variables définies dans la boucle sont perdues lorsque la boucle se termine. Utilisez plutôt le modèle de redirection d'entrée (while ... done < fichier).
Contrôle avancé des boucles et techniques
Des scripts efficaces nécessitent la capacité de contrôler l'exécution des boucles en fonction des conditions d'exécution.
1. Contrôle du flux : break et continue
break: Quitte immédiatement la boucle entière, quelles que soient les itérations ou conditions restantes.continue: Ignore l'itération actuelle et passe immédiatement à l'itération suivante (ou réévalue la conditionwhile).
Exemple : Recherche et arrêt
CIBLE_RECHERCHE="target.conf"
for file in /etc/*; do
if [ -f "$file" ] && [[ "$file" == *"$CIBLE_RECHERCHE"* ]]; then
echo "Configuration cible trouvée à : $file"
break # Arrêter le traitement une fois trouvée
elif [ -d "$file" ]; then
continue # Ignorer les répertoires, vérifier uniquement les fichiers
fi
echo "Vérification du fichier : $file"
done
2. Gestion des délimiteurs complexes à l'aide de IFS
Bien que la lecture de fichiers ligne par ligne nécessite d'effacer IFS, l'itération sur une liste séparée par un caractère différent (comme une virgule) nécessite de définir temporairement IFS.
DONNEES_CSV="data1,data2,data3,data4"
ANCIEN_IFS=$IFS # Sauvegarde de l'IFS d'origine
IFS=',' # Définit IFS sur le caractère virgule
for item in $DONNEES_CSV; do
echo "Élément trouvé : $item"
done
IFS=$ANCIEN_IFS # Restaure l'IFS d'origine immédiatement après la boucle
Avertissement : Modifications globales de
IFSSauvegardez toujours l'
$IFSd'origine avant de le modifier dans un script (par exemple,ANCIEN_IFS=$IFS). Omettre de restaurer la valeur d'origine peut entraîner un comportement imprévisible dans les commandes ultérieures.
Meilleures pratiques pour des boucles Bash robustes
| Pratique | Justification |
|---|---|
| Toujours mettre les variables entre guillemets | Utilisez "$variable" pour empêcher la division de mots et l'expansion de glob, en particulier lors de l'itération sur des fichiers. |
Utiliser while IFS= read -r |
La méthode la plus fiable pour traiter les fichiers ligne par ligne, gérant correctement les espaces et les caractères spéciaux. |
| Vérifier l'existence | Lors de l'utilisation du globbing (*.txt), incluez toujours une vérification (if [ -f "$file" ];) pour vous assurer que la boucle ne traite pas le nom littéral du modèle si aucun fichier ne correspond. |
| Localiser les variables | Utilisez le mot-clé local dans les fonctions pour empêcher les variables de boucle d'écraser accidentellement des variables globales. |
| Utiliser les commandes intégrées plutôt que les commandes externes | Utilisez l'expansion d'accolades ({1..10}) ou les boucles de style C plutôt que de lancer des commandes externes comme seq pour améliorer les performances. |
Conclusion
Les boucles for et while sont fondamentales pour le scripting Bash, permettant des tâches d'automatisation complexes avec une répétition de code minimale. En appliquant systématiquement des modèles robustes – tels que l'approche while IFS= read -r pour le traitement des fichiers et la mise entre guillemets diligente dans les boucles for – vous pouvez créer des scripts fiables, performants et résistants aux formats de données inattendus, apportant une véritable puissance à vos efforts d'automatisation shell.