Commandes affectant le comportement des boucles
Les commandes de contrôle de boucle break et continue [37] 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.
[37] 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.