Commandes affectant le comportement des boucles
Les commandes de contrôle de boucle break et continue [35] correspondent exactement à leur contre-partie dans d'autres langages de programmation. La commande break termine la boucle (en sort), alors que continue fait un saut à la prochaine itération (répétition) de la boucle, oubliant les commandes restantes dans ce cycle particulier de la boucle.
Exemple 10.20. Effets de break et continue dans une boucle
#!/bin/bash LIMITE=19 # Limite haute. echo echo "Affiche les nombres de 1 à 20 (mais pas 3 et 11)." a=0 while [ $a -le "$LIMITE" ] do a=$(($a+1)) if [ "$a" -eq 3 ] || [ "$a" -eq 11 ] # Exclut 3 et 11. then continue # Continue avec une nouvelle itération de la boucle. fi echo -n "$a " # Ceci ne s'exécutera pas pour 3 et 11. done # Exercice : # Pourquoi la boucle affiche-t'elle jusqu'au 20 ? echo; echo echo "Affiche les nombres de 1 à 20, mais quelque chose se passe après 2." ################################################################## # Même boucle, mais en substituant 'continue' avec 'boucle'. a=0 while [ "$a" -le "$LIMITE" ] do a=$(($a+1)) if [ "$a" -gt 2 ] then break # Ne continue pas le reste de la boucle. fi echo -n "$a " done echo; echo; echo exit 0
La commande break peut de façon optionnelle prendre un paramètre. Un simple break termine seulement la boucle interne où elle est incluse mais un break N sortira de N niveaux de boucle.
Exemple 10.21. Sortir de plusieurs niveaux de boucle
#!/bin/bash
# break-levels.sh: Sortir des boucles.
# "break N" sort de N niveaux de boucles.
for boucleexterne in 1 2 3 4 5
do
echo -n "Groupe $boucleexterne: "
# ----------------------------------------------------------
for boucleinterne in 1 2 3 4 5
do
echo -n "$boucleinterne "
if [ "$boucleinterne" -eq 3 ]
then
break # Essayez break 2 pour voir ce qui se passe.
# (Sort des boucles internes et externes.)
fi
done
# ----------------------------------------------------------
echo
done
echo
exit 0
La commande continue, similaire à break, prend un paramètre de façon optionnelle. Un simple continue court-circuite l'itération courante et commence la prochaine itération de la boucle dans laquelle elle se trouve. Un continue N termine toutes les itérations à partir de son niveau de boucle et continue avec l'itération de la boucle N niveaux au-dessus.
Exemple 10.22. Continuer à un plus haut niveau de boucle
#!/bin/bash
# La commande "continue N" continue jusqu'au niveau de boucle N.
for exterieur in I II III IV V # Boucle extérieure
do
echo; echo -n "Groupe $exterieur : "
# ----------------------------------------------------------
for interieur in 1 2 3 4 5 6 7 8 9 10 # Boucle intérieure
do
if [ "$interieur" -eq 7 ]
then
continue 2 # Continue la boucle au deuxième niveau, c'est-à-dire la
#+ boucle extérieure.
# Remplacez la ligne ci-dessus avec un simple "continue"
# pour voir le comportement normal de la boucle.
fi
echo -n "$interieur " # 7 8 9 10 ne s'afficheront jamais.
done
# ----------------------------------------------------------
done
echo; echo
# Exercice :
# Parvenir à un emploi utile pour "continue N" dans un script.
exit 0
Exemple 10.23. Utiliser continue N dans une tâche courante
# Albert Reiner donne un exemple pour l'utilisation de "continue N" :
# -------------------------------------------------------------------
# Supposez que j'ai un grand nombre de jobs à exécuter, avec des données Ã
#+ traiter dans des fichiers dont le nom correspond à un certain modèle
#+ et qui font tous partie d'un même répertoire.
#+ Plusieurs machines accèdent à ce répertoire et je veux distribuer le
#+ travail entre ces différentes machines. Alors, j'exécute ce qui suit
#+ avec nohup sur toutes les machines :
while true
do
for n in .iso.*
do
[ "$n" = ".iso.opts" ] && continue
beta=${n#.iso.}
[ -r .Iso.$beta ] && continue
[ -r .lock.$beta ] && sleep 10 && continue
lockfile -r0 .lock.$beta || continue
echo -n "$beta: " `date`
run-isotherm $beta
date
ls -alF .Iso.$beta
[ -r .Iso.$beta ] && rm -f .lock.$beta
continue 2
done
break
done
# Les détails, en particulier le sleep N, sont spécifiques à mon
#+ application mais le modèle général est :
while true
do
for job in {modèle}
do
{job déjà terminé ou en cours d'exécution} && continue
{indiquez que ce job est en cours d'exécution, exécutez le job, indiquez-le comme terminé}
continue 2
done
break # Ou quelque chose comme `sleep 600' pour éviter la fin.
done
# De cette façon, le script s'arrêtera seulement quand il n'y aura plus de jobs
#+ à faire (en incluant les jobs qui ont été ajoutés à l'exécution). À travers
# l'utilisation de fichiers verrous appropriés, il peut être exécuté sur
#+ plusieurs machines en même temps sans duplication des calculs [qui ont
#+ demandé quelques heures dans mon cas, donc je veux vraiment éviter ceci].
#+ De plus, comme la recherche recommence toujours au début, vous pouvez
coder des priorités dans les noms des fichiers. Bien sûr, vous pouvez le
#+ faire sans `continue 2' mais alors vous devrez vérifier réellement si
#+ un job s'est terminé (pour rechercher immédiatement le prochain
#+ job) ou non (auquel cas nous arrêtons le programme ou l'endormissons
#+ pour un long moment le temps que vous cherchions un autre job)..
La construction continue N est difficile à comprendre et complexe à utiliser dans tous les contextes. Il est probablement raisonnable de l'éviter.
[35] Ce sont des commandes intégrées du shell, alors que les autres commandes de boucle, telles que while et case, sont des mots clés.