10. Boucles et branchements

What needs this iteration, woman?

--Shakespeare, Othello

Les opérations sur les blocs de code sont la clé des scripts shell structurés et organisés. Les syntaxes de boucles et de branchements fournissent les outils pour cela.

10.1. Boucles

Une boucle est un bloc de code qui répète [45] une liste de commandes aussi longtemps que la condition de contrôle de la boucle est vraie.

boucles for

for arg in [liste]

C'est la construction de boucle de base. Elle diffère de façon significative de sa contre-partie en C.

for arg in [liste]
do
commande(s)...
done

[Note]

Note

À chaque passage dans la boucle, arg prend successivement la valeur de toutes les variables de la liste.

for arg in "$var1" "$var2" "$var3" ... "$varN"
# Lors du tour 1 de la boucle, arg = $var1
# Lors du tour 2 de la boucle, arg = $var2
# Lors du tour 3 de la boucle, arg = $var3
# ...
# Lors du tour N de la boucle, arg = $varN

#  Les arguments dans [liste] sont mis entre guillemets pour empêcher une
#+ possible séparation des mots.

L'argument liste peut contenir des caractères joker.

Si do est sur la même ligne que for, il est impératif d'avoir un point virgule après la liste.

for arg in [liste] ; do

Exemple 10.1. Des boucles for simples

&ex22;

Chaque élément de la [liste] peut contenir de multiples paramètres. C'est utile pour travailler sur des paramètres en groupe. Dans de tels cas, utilisez la commande set (voir l'Exemple 14.16, « Utiliser set avec les paramètres de position ») pour forcer l'analyse de chaque élément de la [liste] et l'affectation de chaque composant aux paramètres positionnels.

Exemple 10.2. Boucle for avec deux paramètres dans chaque élément de la [liste]

&ex22a;

Une variable peut fournir la [liste] dans une boucle for.

Exemple 10.3. Fileinfo : opérer sur une liste de fichiers contenue dans une variable

&fileinfo;

Si la [liste] dans une boucle for contient des caractères joker (* et ?) utilisés dans le remplacement des noms de fichier, alors l'expansion des noms de fichiers a lieu.

Exemple 10.4. Agir sur des fichiers à l'aide d'une boucle for

&listglob;

Omettre la partie in [liste] d'une boucle for fait en sorte que la boucle opère sur $@, les paramètres de position. Une illustration particulièrement intelligente de ceci est l'Exemple A.15, « Générer des nombres premiers en utilisant l'opérateur modulo ». Voir aussi Exemple 14.17, « Inverser les paramètres de position ».

Exemple 10.5. in [liste] manquant dans une boucle for

&ex23;

Il est possible d'utiliser la substitution de commandes pour générer la [liste] d'une boucle for. Voir aussi l'Exemple 15.54, « Utiliser seq pour générer l'incrément d'une boucle », l'Exemple 10.10, « Afficher les liens symboliques dans un répertoire » et l'Exemple 15.48, « Conversion de base ».

Exemple 10.6. Générer la [liste] dans une boucle for avec la substitution de commandes

&forloopcmd;

Voici un exemple un peu plus complexe de l'utilisation de la substitution de commande pour créer la [liste].

Exemple 10.7. Un remplaçant de grep pour les fichiers binaires

&bingrep;

Un peu la même chose.

Exemple 10.8. Afficher tous les utilisateurs du système

&userlist;

Encore un exemple d'une [liste] résultant d'une substitution de commande.

Exemple 10.9. Rechercher les auteurs de tous les binaires d'un répertoire

&findstring;

Un dernier exemple de [list] / substitution de commande, avec cette fois une « commande » qui est une fonction.

genere_liste ()
{
  echo "un deux trois"
}

for mot in $(genere_liste)  
         # "mot" va chercher le résultat de la fonction
do
  echo "$mot"
done

# un
# deux
# trois

La sortie d'une boucle for peut être envoyée via un tube à une ou plusieurs commandes.

Exemple 10.10. Afficher les liens symboliques dans un répertoire

&symlinks;

Le stdout d'une boucle peut être redirigé vers un fichier, comme cette légère modification du précédent exemple le montre.

Exemple 10.11. Liens symboliques dans un répertoire, sauvés dans un fichier

&symlinks2;

Il existe une autre syntaxe pour une boucle for ressemblant fortement à celle du C. Elle nécessite des parenthèses doubles.

Exemple 10.12. Une boucle for comme en C

&forloopc;

Voir aussi l'Exemple 26.15, « Application complexe des tableaux Exploration d'une étrange série mathématique », l'Exemple 26.16, « Simuler un tableau à deux dimensions, puis son test » et l'Exemple A.6, « Séries de Collatz ».

---

Maintenant, une boucle for utilisée dans un contexte de la « vie quotidienne ».

Exemple 10.13. Utiliser efax en mode batch

&ex24;

while

Cette construction teste une condition au début de la boucle et continue à boucler tant que la condition est vraie (renvoie un 0 comme code de sortie). Par opposition à une boucle for, une boucle while trouve son utilité dans des situations où le nombre de répétitions n'est pas connu dès le départ.

while [ condition ]
do
commande(s)...
done

La syntaxe avec crochets dans une boucle while n'est rien d'autre que notre vieille connaissance, le test entre crochets utilisé dans un test if/then. En réalité, une boucle while peut de manière tout à fait correcte utiliser la syntaxe plus souple avec doubles crochets (while [[ condition ]]).

Comme c'est le cas avec les boucles for, placer le do sur la même ligne que le test de la condition nécessite un point virgule.

while [ condition ] ; do

Note that the test brackets are not mandatory in a while loop. See, for example, the getopts construct.

Exemple 10.14. Simple boucle while

&ex25;

Exemple 10.15. Une autre boucle while

&ex26;

Une boucle while peut avoir de multiples conditions. Seule la condition finale détermine quand la boucle se termine. Malgré tout, ceci nécessite une syntaxe de boucle légèrement différente.

Exemple 10.16. Boucle while avec de multiples conditions

&ex26a;

Comme pour une boucle for, une boucle while peut employer une syntaxe identique à celle de C, avec les parenthèses doubles (voir aussi l'Exemple 9.33, « Manipulation, à la façon du C, de variables »).

Exemple 10.17. Syntaxe à la C pour une boucle while

&whloopc;

À l'intérieur des crochets de test, une boucle while peut appeler une fonction.

t=0

condition ()
{
  ((t++))

  if [ $t -lt 5 ]
  then
    return 0  # true
  else
    return 1  # false
  fi
}

while condition
#     ^^^^^^^^^
#     Appel de fonction -- quatre itérations de boucle.
do
  echo "Toujours en cours : t = $t"
done

# Toujours en cours : t = 1
# Toujours en cours : t = 2
# Toujours en cours : t = 3
# Toujours en cours : t = 4

En couplant la puissance de la commande read avec une boucle while, nous obtenons la syntaxe while read, qui s'avère bien utile pour lire et analyser des fichiers.

cat $nomfichier |   # Fournit des informations à partir d'un fichier.
while read ligne   # Tant qu'il y a une nouvelle ligne à lire...
do
  ...
done

# =========== Snippet from "sd.sh" example script ========== #

  while read value   # Read one data point at a time.
  do
    rt=$(echo "scale=$SC; $rt + $value" | bc)
    (( ct++ ))
  done

  am=$(echo "scale=$SC; $rt / $ct" | bc)

  echo $am; return $ct   # This function "returns" TWO values!
  #  Caution: This little trick will not work if $ct > 255!
  #  To handle a larger number of data points,
  #+ simply comment out the "return $ct" above.
} <"$datafile"   # Feed in data file.

[Note]

Note

Une boucle while peut avoir son entrée stantard redirigée vers un fichier par un < à la fin.

Une boucle while peut avoir son entrée standard (stdin) fourni via un tube.

until

Cette construction teste une condition au début de la boucle et continue à boucler tant que la condition est fausse (le contraire de la boucle while).

until [ condition-est-vraie ]
do
commande(s)...
done

Notez qu'une boucle until teste la condition de fin au début de la boucle, contrairement aux constructions similaires dans certains langages de programmation.

Comme pour les boucles for, placer do sur la même ligne que le test de la condition nécessite un point virgule.

until [ condition-est-vraie ] ; do

Exemple 10.18. Boucle until

&ex27;

Comment choisir entre une boucle for, une boucle while et une boucle until ? En C, vous utiliserez typiquement une boucle for quand le nombre d'itérations est déjà connu. Néanmoins, avec Bash, la situation est plus compliquée. La boucle for en Bash est moins structurée et plus flexible que son équivalent dans d'autres langages. Du coup, n'hésitez pas à utiliser le type de boucle qui vous permet de faire ce que vous souhaitez de la façon la plus simple.



[45] Itération : exécution répétée d'une commande ou d'un groupe de commandes, en général -- mais pas toujours, tant qu' une certaine condition reste vraie ou jusqu'à ce qu' une certaine condition devienne vraie.