Quelques notions sur les boucles dans bash

Aujourd'hui je reviens avec un petit baratin sur les boucles dans les scripts bash. C'est très superficiel, mais ça peut servir de point de départ aux débutants qui nous lisent.

Bash permet de gérer les types classiques de boucles : for, while, et until. Et cela n'a rien de bien excitant, je vous l'accorde. Ce qui est plus intéressant ce sont les multiples moyens que l'on a de "nourrir" ces boucles.
Passons tout d'abord sur les généralités.

La boucle for.

Elle s'articule autour de ce schéma :

for VAR in LISTE
do
# actions
done 

VAR est ma variable, LISTE est une liste d'éléments. Cela donne par exemple :

for i in 1 2 3
do
echo "i =" $i
done 

résultat :

i = 1
i = 2
i = 3

Il existe néanmoins un schéma alternatif à cette syntaxe. Il est possible de définir une boucle for selon le modèle suivant :

for ((initialisation de VAR; contrôle de VAR; modification de VAR))
do
# actions
done 

Ce qui permet par exemple de coder un compte à rebours de 10 à 0:

for ((i = 10; i >= 0; i -= 1))
do
echo $i
done 

La boucle while.

La boucle while s'écrit sous cette forme générale :

while CONDITION
do
# actions
done 

CONDITION est une condition de continuation de la boucle. Tant que cette condition est vraie, la boucle continue. Il faut presque toujours définir les variables de CONDITION avant le while, sinon la condition n'est pas vérifiable. Mais nous verrons qu'il y a une exception.

Un exemple pour la route :

i=0
while [ $i -le 10 ]
do
echo $i
let i=1+$i
done 

Je pose que i vaut 0, et je dis que ma boucle doit s'exécuter tant que i est inférieur ou égal à 10 (man test pour la syntaxe dans les crochets). Remarquez que je suis obligé d'incrémenter manuellement le compteur i.

Comme pour for, on peut recourir à cette syntaxe :

i=0
while ((i <= 10))
do
echo $i
((i += 1))
done 

Cependant, l'utilisation des crochets offre une plus grande richesse.

La boucle until.

Elle est tout à fait comparable à la boucle while, donc je ne rentre pas dans les détails. Par contre, elle se différencie de cette dernière par le fait que la condition est une condition d'arrêt, et non de continuation, de la boucle.
Donc la boucle until s'arrête quand CONDITION est vraie, alors que la boucle while continue tant que CONDITION est vraie.

Nourrir le monstre.

Maintenant que l'on a de quoi faire des boucles, intéressons-nous aux moyens de les alimenter.
La boucle for est la plus simple à faire fonctionner pour le novice car elle parcoure une liste définie d'éléments.
Cette liste peut être totalement statique, elle peut être une variable définie précédemment dans le script, ou elle peut être obtenue à partir d'une commande. Par ex :

for i in `jot -r 5`
do
echo $((i-100))
done 

jot est une commande de Mac OS X (et FreeBSD entre autre) qui permet de générer toutes sortes de séries de chiffres ou de lettres. Ici la commande `jot -r 5` génère 5 nombres aléatoires. On peut remplacer le `echo $((i-100))` par quelque chose de plus intéressant ;).

Il y a bien d'autres moyens d'écrire cette même boucle. Deux exemples au hasard :

for i in `jot -r 5`; do echo $((i-100)); done 

et

for i in $(jot -r 5); do
echo $((i-100))
done

Si vous souhaitez aller plus loin et découvrir le potentiel de jot, seq et bash dans la génération de séquences de chiffres ou de lettres, n'hésitez pas à lire cet article : jot et seq, créer des séquences en ligne de commande.

Pour les boucles while et until, la contrainte est différente. Peu importe ce qu'on donne à l'opérateur, ce qui est pris en compte c'est le status (vrai ou faux, succès ou échec, ...). En général, ce status est obtenu à partir d'un test :

while [ "$var" = "toto" ]; do
# actions
done 

Mais on peut aussi nourrir une boucle while (plus rarement until) avec d'autres choses, comme un fichier texte :

num=0
while read ligne; do
num=$((num+1))
echo "$num   $ligne"
done < /etc/passwd 

Dans ce cas, la boucle s'arrête quand il n'y a plus de ligne à lire dans le fichier. La syntaxe "read VARIABLE" est utilisable aussi dans le cas d'un résultat de commande, mais il faut alors utiliser un pipe pour nourrir le "read" :

num=0
ls | while read ligne; do
num=$((num+1))
echo "$num   $ligne"
done 

Voilà un tour sommaire sur les boucles en bash.
La discussion a lieu par ici.

Pour aller un peu plus loin, n'hésitez pas à consulter les autres articles qui parlent de bash !

À lire aussi :

3 comments

  1. je ve faire un programme en bache qui génére un nombre aleatoire et qui demande a l"utilisateur de entrer un nombre j'usqu'as qu'il trouve le nombre mystere et en m^m temp reduire la plage du RANDOM du 32767 a 100 autrement dit le bombre mystere doit pas deppaser 100 voila merci bq

  2. C'est gentil de passer nous voir, mais en général je me fais payer pour faire le boulot des autres.
    Rapidement, sans trop tester, voici un début de piste :

    # nombre entre 0 et 100
    MONRAND=$(jot -r 1 0 100)
    # nombre de tentatives
    TENTATIVES=0
    # initialisation de l'entrée
    INPUT=101
    # boucle 
    while [ $INPUT -ne $MONRAND ]; do 
      read -p "donnez un nombre entre 0 et 100 : " INPUT
      TENTATIVES=$((TENTATIVES+1))
    done
    # fin
    echo "Il fallait trouver ${MONRAND}. 
    Vous avez tenté ${TENTATIVES} fois votre chance"
  3. Un grand merci pour ces pages d'une grande qualité sur bash.

    J'ai eu besoin d'info pour automatiser un traitement ocr avec tesseract de plusieurs pages et vos pages ont été très utiles.

    Un travail propre et pro, trop rare sur le web.

    Bonne continuation ;)

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *