Bash propose deux formes de boucles :
for
Pour parcourir une liste d'éléments, on utilise la boucle for.
for varname in words; do COMMANDS; done
words est développé par le découpage des mots et l'expansion des noms de fichiers (dont on a parlé dans le concept Citations).
Chaque mot est affecté tour à tour à varname, et les COMMANDS sont exécutées.
Voici quelques exemples qui montrent quand la boucle for peut être utile
Exécuter des commandes sur un groupe de fichiers.
# source all the bash library files in the current directory
for file in ./*.bash; do
source "$file"
done
Exécuter une commande sur chacun des paramètres d'un script ou d'une fonction.
for arg in "$@"; do
echo "argument: ${arg}"
done
Exécuter une commande pour chaque mot séparé par un espace dans la sortie d'une commande.
for i in $(seq 10); do
echo "${i} squared is $((i * i))"
done
On verra plus loin quelques avertissements à propos de ce style.
for arithmétiqueBash dispose bien d'une boucle arithmétique. Elle te semblera sans doute familière si tu connais d'autres langages de programmation.
for ((INITIALIZATION; CONDITION; INCREMENT)); do COMMANDS; done
Les doubles parenthèses en bash représentent un contexte arithmétique (on verra plus de détails sur l'arithmétique de bash dans un prochain concept).
L'exemple ci-dessus avec seq peut s'écrire comme ceci :
for ((i = 1; i <= 10; i++)); do
echo "${i} squared is $((i * i))"
done
for
Ne lis pas de lignes avec for.
C'est un anti-pattern que l'on voit souvent : parcourir la sortie de cat.
for line in $(cat some.file); do
do_something_with "$line"
done
C'est faux pour 2 raisons.
for parcourt les mots du fichier, pas les lignes.Comme on l'a vu dans le concept Citations, le découpage des mots peut être contrôlé avec la variable IFS, et l'expansion des noms de fichiers peut être désactivée.
Mais c'est souvent une solution fragile.
for n'est pas la bonne méthode pour parcourir les lignes d'un fichier.
La façon idiomatique de lire un fichier est d'utiliser une boucle while.
while
Utilise while pour répéter une suite de commandes _tant qu'_une condition reste vraie.
while CONDITION_COMMANDS; do COMMANDS; done
Comme pour if (dont on a parlé dans le concept Conditionnelles, il n'y a pas de syntaxe particulière pour CONDITION_COMMANDS.
Le code de sortie de la liste de commandes déterminera si c'est « vrai » ou « faux ».
La commande break sort de la boucle.
L'exécution reprend à la commande qui suit le done final de la boucle.
La commande continue passe à l'itération suivante de la boucle.
Comme on l'a dit, une boucle while est la façon idiomatique de lire un fichier.
while IFS= read -r line; do
do_something_with "$line"
done < some.file
Le contenu du fichier est fourni en entrée à la boucle par la redirection <.
La commande read renvoie « vrai » si elle peut lire une ligne complète depuis son entrée.
Quand l'entrée est épuisée, ou si la dernière ligne ne se termine pas par un retour à la ligne, read renvoie « faux ».
La façon vraiment idiomatique de lire les lignes d'un fichier, même si la dernière ligne ne se termine pas par un retour à la ligne, est
while IFS= read -r line || [[ -n "$line" ]]; do ...
L'option -r demande à read de ne pas interpréter les séquences d'échappement : une barre oblique inverse est un simple caractère.
IFS= affecte la string vide à IFS uniquement pour la durée de la commande read.
Cela désactive temporairement le découpage des mots, de sorte que les espaces en début ou en fin de la ligne de texte entrante soient conservés.
until
La construction until répète une suite de commandes tant qu'une condition est fausse.
La boucle se répète jusqu'à ce que la condition devienne vraie.
until CONDITION_COMMANDS; do COMMANDS; done
Il est rare d'utiliser until.
Il est plus courant d'utiliser une boucle « while not ».
while ! CONDITION_COMANDS; do ...
Parfois, on veut boucler indéfiniment. Voici deux façons de faire.
une boucle while avec une condition dont le code de sortie est toujours un succès
while true; do ...
une boucle for arithmétique avec des expressions vides
for ((;;)); do ...
Il n'existe pas de construction do-while explicite, mais on peut obtenir le même effet :
while true; do
COMMANDS
if END_CONDITION; then
break
fi
done