Tout ce que vous devez savoir sur Bash For Loops sous Linux

Les scripts bash sont un moyen très efficace d'automatiser les tâches, en particulier celles qui tirent parti d'autres programmes existants. Cette automatisation nécessite souvent de répéter plusieurs fois une opération similaire, c'est précisément là que la boucle for prend tout son sens.

Les administrateurs système Linux et Mac sont généralement familiarisés avec les scripts via le terminal, mais même les utilisateurs Windows peuvent participer à l'action avec le sous-système Windows pour Linux .

Fonctionnement des scripts Bash

Un script bash est simplement un fichier texte contenant une série de commandes que le shell bash peut lire et exécuter. Bash est le shell par défaut dans macOS pré-Catalina et dans la plupart des distributions Linux.

Si vous n'avez jamais travaillé avec un script shell auparavant, vous devriez commencer par le cas le plus simple. Cela vous permettra de mettre en pratique les concepts clés, y compris la création du script et son exécution.

Tout d'abord, créez le fichier suivant dans un emplacement pratique (idéalement, ouvrez un terminal et accédez d'abord au répertoire souhaité):

 #!/bin/bash
echo "Hello, World"

La première ligne indique à tout ce qui exécute ce programme comment l'exécuter (c'est-à-dire en utilisant l'interpréteur bash). La seconde est juste une commande comme toute autre que vous pourriez entrer sur la ligne de commande. Enregistrez ce fichier sous hello_world.sh , puis:

 $ chmod +x hello_world.sh
$ ./hello_world.sh

La commande chmod sur la première ligne rend le fichier exécutable, ce qui signifie qu'il peut être exécuté en tapant son nom, comme dans la deuxième ligne.

Si vous voyez les mots «Hello, World» apparaître sur une ligne de votre terminal, alors tout fonctionne comme vous le souhaitez.

Comment fonctionnent les boucles

En programmation générale, il existe deux types principaux de boucle for: numérique et foreach . Le type numérique est traditionnellement le plus courant, mais dans l'utilisation de bash, c'est généralement l'inverse.

Les boucles for numériques se concentrent généralement sur un seul entier qui détermine le nombre d'itérations à effectuer, par exemple:

 for (i = 0; i < 100; i++) {
/* statements to execute repeatedly */
}

Il s'agit d'une boucle familière pour qui répétera exactement 100 fois, à moins que i ne soit modifié dans la boucle, ou qu'une autre instruction ne provoque l'arrêt de l'exécution de la boucle for.

Les boucles Foreach, en revanche, ont tendance à fonctionner sur des structures telles que des listes ou des tableaux, et à itérer pour chaque élément de cette collection:

 people = [ "Peter", "Paul", "Mary" ]
foreach (people as person) {
if (person == "Paul") {
...
}
}

Certaines langues utilisent une syntaxe légèrement différente qui permute l'ordre de la collection et de l'élément:

 people = [ "Peter", "Paul", "Mary" ]
for (person in people) {
if (person == "Paul") {
...
}
}

Pour dans les boucles

Dans bash, la boucle foreach ou for in est plus courante. La syntaxe de base est, simplement:

 for arg in [list]
do
/* statements to execute repeatedly */
/* the value of arg can be obtained using $arg */
done

Par exemple, pour parcourir trois fichiers nommés explicitement:

 for file in one.c two.c three.c
do
ls "$file"
done

Si de tels fichiers existent dans le répertoire courant, la sortie de ce script sera:

 one.c
two.c
three.c

Au lieu d'un ensemble fixe de fichiers, la liste peut être obtenue via un modèle glob (un comprenant des jokers – caractères spéciaux qui représentent d'autres caractères). Dans l'exemple suivant, la boucle for effectue une itération sur tous les fichiers (dans le répertoire actuel) dont les noms se terminent par «.xml»:

 for file in *.xml
do
ls -l "$file"
done

Voici un exemple de sortie:

 $ -rw-r--r-- 1 bobby staff 2436 3 Nov 2019 feed.xml
$ -rw-r--r-- 1 bobby staff 6447 27 Oct 16:24 sitemap.xml

Cela peut ressembler beaucoup à une façon de faire de longue haleine:

 $ ls -l *.xml

Mais il y a une différence significative: la boucle for exécute le programme ls deux fois, avec un seul nom de fichier qui lui est passé à chaque fois. Dans l'exemple ls séparé, le modèle glob (* .xml) correspond d'abord aux noms de fichiers, puis les envoie tous, en tant que paramètres de ligne de commande individuels, à une instance de ls .

Voici un exemple qui utilise le programme wc (word count) pour rendre la différence plus évidente:

 $ wc -l *.xml
44 feed.xml
231 sitemap.xml
275 total

Le programme wc compte le nombre de lignes dans chaque fichier séparément, puis imprime un compte total sur chacun d'eux. En revanche, si wc fonctionne dans une boucle for:

 for file in *.xml
do
wc -l $file
done

Vous verrez toujours le nombre pour chaque fichier:

 44 feed.xml
231 sitemap.xml

Mais il n'y a pas de total récapitulatif global car wc est exécuté de manière isolée à chaque itération de la boucle.

Lorsqu'une liste n'est pas une liste

Il y a une erreur très simple et courante lors du traitement des boucles for, en raison de la façon dont bash gère les arguments / chaînes entre guillemets. La lecture en boucle d'une liste de fichiers doit être effectuée comme suit:

 for file in one.c two.c

Pas comme ça:

 for file in "one.c two.c"

Le deuxième exemple place les noms de fichiers entre guillemets, ce qui donne une liste avec un seul paramètre; la boucle for ne s'exécutera qu'une seule fois. Ce problème peut être évité en utilisant une variable dans de tels cas:

 FILES="one.c two.c"
for file in $FILES
do
...
done

Notez que la déclaration de variable elle-même doit mettre sa valeur entre guillemets!

Pour sans liste

Sans rien à parcourir, une boucle for opère sur les arguments de ligne de commande fournis au script lors de son appel. Par exemple, si vous avez un script nommé args.sh contenant les éléments suivants:

 #!/bin/sh
for a
do
echo $a
done

Ensuite, exécuter args.sh vous donnera ce qui suit:

 $ ./args.sh one two three
one
two
three

Bash reconnaît ce cas et traite pour a faire comme l'équivalent de pour a dans $ @ do où $ @ est une variable spéciale représentant les arguments de la ligne de commande.

Émulation d'une boucle For numérique traditionnelle

Les scripts bash traitent souvent des listes de fichiers ou des lignes de sortie d'autres commandes, de sorte que le type de boucle for in est courant. Cependant, l'opération traditionnelle de style C est toujours prise en charge:

 for (( i=1; i<=5; i++ ))
do
echo $i
done

Il s'agit de la forme classique en trois parties dans laquelle:

  1. une variable est initialisée (i = 1) lors de la première rencontre de la boucle
  2. la boucle continue tant que la condition (i <= 5) est vraie
  3. à chaque fois autour de la boucle, la variable est incrémentée (i ++)

Itérer entre deux valeurs est une exigence assez courante pour qu'il existe une alternative plus courte et légèrement moins déroutante:

 for i in {1..5}
do
echo $i
done

L'expansion d'accolade qui a lieu traduit efficacement la boucle for ci-dessus en:

 for i in 1 2 3 4

Contrôle de boucle plus fin avec pause et continue

Les boucles for plus complexes nécessitent souvent un moyen de quitter tôt ou de redémarrer immédiatement la boucle principale avec la valeur suivante à son tour. Pour ce faire, bash emprunte les instructions break et continue qui sont courantes dans d'autres langages de programmation. Voici un exemple qui utilise les deux pour trouver le premier fichier de plus de 100 caractères:

 #!/bin/bash
for file in *
do
if [ ! -f "$file" ]
then
echo "$file is not a file"
continue
fi
num_chars=$(wc -c < "$file")
echo $file is "$num_chars characters long"
if [ $num_chars -gt 100 ]
then
echo "Found $file"
break
fi
done

La boucle for opère ici sur tous les fichiers du répertoire courant. Si le fichier n'est pas un fichier normal (par exemple s'il s'agit d'un répertoire), l'instruction continue est utilisée pour redémarrer la boucle avec le fichier suivant à son tour. S'il s'agit d'un fichier normal, le deuxième bloc conditionnel déterminera s'il contient plus de 100 caractères. Si tel est le cas, l'instruction break est utilisée pour quitter immédiatement la boucle for (et atteindre la fin du script).

Conclusion

Un script bash est un fichier contenant un ensemble d'instructions qui peuvent être exécutées. Une boucle for permet de répéter une partie d'un script plusieurs fois. Grâce à l'utilisation de variables, de commandes externes et des instructions break et continue, les scripts bash peuvent appliquer une logique plus complexe et exécuter un large éventail de tâches.