Commandes affectant le comportement des boucles
Les commandes de contrôle de boucle break et continue [1] 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 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 un nouvelle itération de la boucle. fi echo -n "$a " 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 " # 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 gives an example of how to use "continue N":
# ---------------------------------------------------------
# Suppose I have a large number of jobs that need to be run, with
#+ any data that is to be treated in files of a given name pattern in a
#+ directory. There are several machines that access this directory, and
#+ I want to distribute the work over these different boxen. Then I
#+ usually nohup something like the following on every box:
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
# The details, in particular the sleep N, are particular to my
#+ application, but the general pattern is:
while true
do
for job in {pattern}
do
{job already done or running} && continue
{mark job as running, do job, mark job as done}
continue 2
done
break # Or something like `sleep 600' to avoid termination.
done
# This way the script will stop only when there are no more jobs to do
#+ (including jobs that were added during runtime). Through the use
#+ of appropriate lockfiles it can be run on several machines
#+ concurrently without duplication of calculations [which run a couple
#+ of hours in my case, so I really want to avoid this]. Also, as search
#+ always starts again from the beginning, one can encode priorities in
#+ the file names. Of course, one could also do this without `continue 2',
#+ but then one would have to actually check whether or not some job
#+ was done (so that we should immediately look for the next job) or not
#+ (in which case we terminate or sleep for a long time before checking
#+ for a new job). |
![]() | La construction continue N est difficile à comprendre et complexe à utiliser dans tous les contextes. Il est probablement raisonnable de l'éviter. |
| [1] | 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. |
| Précédent | Sommaire | Suivant |
| Boucles imbriquées | Niveau supérieur | Tests et branchements |