Qu'est-ce qu'une boucle Bash for ?
Une boucle for bash est une instruction du langage de programmation bash qui permet l'exécution répétée d'un code. Une boucle for est classée comme une instruction d'itération, c'est-à-dire qu'il s'agit de la répétition d'un processus dans un script bash. Par exemple, vous pouvez exécuter une commande ou une tâche UNIX 5 fois ou lire et traiter une liste de fichiers en utilisant une boucle for. Une boucle for peut être utilisée à l'invite du shell ou dans un script shell lui-même.
Exigences | Linux ou Unix |
Privilèges de la racine | Non |
Niveau de difficulté | Facile |
Catégorie | Scripting shell Linux |
Conditions préalables | Bash |
Compatibilité avec les systèmes d'exploitation | BSD-Linux-macOS-Unix |
Durée de lecture estimée | 9 minutes |
Table des matières ↓
|
syntaxe de la boucle for ↑
Les plages numériques pour la syntaxe sont les suivantes :
for VARIABLE in 1 2 3 4 5 .. N do command1 command2 commandN done
OU
for VARIABLE in file1 file2 file3 do command1 on $VARIABLE command2 commandN done
OU
for OUTPUT in $(Linux-Or-Unix-Command-Here) do command1 on $OUTPUT command2 on $OUTPUT commandN done
Exemples ↑
Ce type de boucle for est caractérisé par le comptage. La plage est spécifiée par un numéro de début (#1) et de fin (#5). La boucle for exécute une séquence de commandes pour chaque membre d'une liste d'éléments. Un exemple représentatif en BASH est le suivant pour afficher le message de bienvenue 5 fois avec la boucle for :
#!/bin/bash for i in 1 2 3 4 5 do echo "Welcome $i times" done
Parfois, vous pouvez avoir besoin de définir une valeur de pas (permettant de compter par deux ou de compter à rebours par exemple). Dernière version de bash version 3.0 a un support intégré pour la mise en place de plages :
#!/bin/bash for i in {1..5} do echo "Welcome $i times" done
Bash v4.0 dispose d'un support intégré permettant de définir une valeur de pas en utilisant {START..FIN..INCREMENT} syntaxe :
#!/bin/bash echo "Bash version ${BASH_VERSION}..." for i in {0..10..2} do echo "Welcome $i times" done
Exemples de résultats :
Bash version 4.0.33(0)-release... Welcome 0 times Welcome 2 times Welcome 4 times Welcome 6 times Welcome 8 times Welcome 10 times
La commande seq pour créer un bash standard pour Loop (méthode dépassée) ↑
AVERTISSEMENT ! La commande seq imprime une séquence de nombres et elle est ici pour des raisons historiques. Les exemples suivants ne sont recommandés que pour les anciennes versions de bash. Il est recommandé à tous les utilisateurs (bash v3.x ) d'utiliser la syntaxe ci-dessus.
La commande seq peut être utilisée comme suit. Un exemple représentatif de seq est le suivant :
#!/bin/bash for i in $(seq 1 2 20) do echo "Welcome $i times" done
Il n'y a aucune bonne raison d'utiliser une commande externe telle que seq pour compter et incrémenter les nombres dans la boucle for, il est donc recommandé d'éviter d'utiliser seq. Les commandes intégrées sont rapides.
Syntaxe des boucles for bash à trois expressions ↑
Ce type de boucle for partage un héritage commun avec le langage de programmation C. Il est caractérisé par une expression de contrôle de boucle à trois paramètres, composée d'un initialisateur (EXP1), d'un test ou d'une condition de boucle (EXP2) et d'une expression de comptage/étape (EXP3).
for (( EXP1; EXP2; EXP3 )) do command1 command2 command3 done ## The C-style Bash for loop ## for (( initializer; condition; step )) do shell_COMMANDS done
Un exemple représentatif de trois expressions dans bash est le suivant :
#!/bin/bash # set counter 'c' to 1 and condition # c is less than or equal to 5 for (( c=1; c<=5; c++ )) do echo "Welcome $c times" done
Exemple de sortie :
Welcome 1 times Welcome 2 times Welcome 3 times Welcome 4 times Welcome 5 times
Comment utiliser for comme boucles infinies ? ↑
Une boucle for infinie peut être créée avec des expressions vides, telles que :
#!/bin/bash for (( ; ; )) do echo "infinite loops [ hit CTRL+C to stop]" done
Sortie conditionnelle avec rupture↑
Vous pouvez effectuer une sortie anticipée avec l'instruction break à l'intérieur de la boucle for. Vous pouvez sortir de l'intérieur d'une boucle FOR, WHILE ou UNTIL en utilisant l'instruction break. Instruction break générale à l'intérieur de la boucle for :
for I in 1 2 3 4 5 do statements1 #Executed for all values of ''I'', up to a disaster-condition if any. statements2 if (disaster-condition) then break #Abandon the loop. fi statements3 #While good and, no disaster-condition. done
Le script shell suivant va parcourir tous les fichiers stockés dans le répertoire /etc. La boucle for sera abandonnée lorsque le fichier /etc/resolv.conf sera trouvé.
#!/bin/bash for file in /etc/* do if [ "${file}" == "/etc/resolv.conf" ] then countNameservers=$(grep -c nameserver /etc/resolv.conf) echo "Total ${countNameservers} nameservers defined in ${file}" break fi done
Poursuite anticipée avec déclaration de poursuite ↑
Pour reprendre l'itération suivante de la boucle FOR, WHILE ou UNTIL qui l'entoure, utilisez l'instruction continue.
for I in 1 2 3 4 5 do statements1 #Executed for all values of ''I'', up to a disaster-condition if any. statements2 if (condition) then continue #Go to next iteration of I in the loop and skip statements3 fi statements3 done
Ce script fait une sauvegarde de tous les noms de fichiers spécifiés sur la ligne de commande. Si le fichier .bak existe, il ignorera la commande cp.
#!/bin/bash FILES="$@" for f in $FILES do # if .bak backup file exists, read next file if [ -f ${f}.bak ] then echo "Skiping $f file..." continue # read next file and skip the cp command fi # we are here means no backup file exists, just use cp command to copy file /bin/cp $f $f.bak done
Boucle For avec des éléments de tableau ↑
Dans cet exemple, nous utilisons la boucle for pour itérer sur un tableau d'éléments définis comme suit :
DB_AWS_ZONE=('us-east-2a' 'us-west-1a' 'eu-central-1a') for zone in "${DB_AWS_ZONE[@]}" do echo "Creating rds (DB) server in $zone, please wait ..." aws rds create-db-instance --availability-zone "$zone" --allocated-storage 20 --db-instance-class db.m1.small --db-instance-identifier test-instance --engine mariadb --master-username my_user_name --master-user-password my_password_here done
Boucle avec une variable shell ↑
Parfois, nous stockons des données importantes dans la variable shell, et nous pouvons utiliser une boucle for comme suit pour lire les données :
_admin_ip="202.54.1.33|MUM_VPN_GATEWAY 23.1.2.3|DEL_VPN_GATEWAY 13.1.2.3|SG_VPN_GATEWAY" for e in $_admin_ip do ufw allow from "${e%%|*}" to any port 22 proto tcp comment 'Open SSH port for ${e##*|}' done
Boucle avec un numéro ↑
Nous pouvons spécifier une plage dans les boucles comme suit :
for i in {START..END} do commands done ## step value ## for i in {START..END..STEP} do commands done ## example: ping cbz01, cbz02, cbz03, and cbz04 using a loop ## for i in 0{1..4} do h="cbz${i}" ping -c 1 -q "$h" &>/dev/null if [ $? -eq 0 ] then echo "server $h alive" else echo "server $h dead or can not ping." fi done
Boucle avec cordes
Disons que nous avons une variable nommée PKGS, et que nous devons parcourir en boucle une liste de chaînes de caractères pour installer ces paquets :
PKGS="php7-openssl-7.3.19-r0 php7-common-7.3.19-r0 php7-fpm-7.3.19-r0 php7-opcache-7.3.19-r0 php7-7.3.19-r0" for p in $PKGS do echo "Installing $p package" sudo apk add "$p" done
Substitution de commande ↑
La substitution de commande consiste à exécuter une commande shell et à enregistrer sa sortie dans une variable. Par exemple :
up=$(uptime) echo "Server uptime is $up"
La liste d'arguments de la boucle for permet également de substituer des commandes comme suit :
for var in $(command) do print "$var" done ## example ## for f in $(ls /nas/*.pdf) do print "File $f" done
Arguments de la ligne de commande ↑
Un argument de ligne de commande n'est rien d'autre qu'un argument envoyé à un programme appelé. Un programme peut prendre un nombre quelconque d'arguments de ligne de commande. Par exemple, nous allons utiliser la commande grep pour rechercher les noms d'utilisateurs dans le fichier /etc/passwd :
$ grep vivek /etc/passwd
grep est le nom d'une commande réelle et le shell exécute cette commande lorsque vous tapez command à l'invite du shell. Le premier mot de la ligne de commande est :
- grep - nom de la commande à exécuter.
- Tout le reste de la ligne de commande est pris comme arguments de cette commande.
La liste d'arguments de la boucle for accpagne également les arguments/paramètres de la ligne de commande comme suit :
## $@ expands to the positional parameters, starting from one. ## for i in $@ do echo "Script arg is $i" done
Vous l'exécutez comme suit :
./script one foo bar
Tout mettre ensemble ↑
Bash for loop est utile pour automatiser les tâches répétitives en informatique. Voyons comment exécuter une commande simple (telle que uptime) sur plusieurs serveurs Linux ou Unix :
for s in server1 server2 server3 do ssh vivek@${s} "uptime" done
OU combine la commande echo avec la substitution de commande comme suit :
for s in server1 server2 server3 do echo "Server ${s}: $(ssh vivek@${s} uptime)" done
Exemples de résultats :
Server server1: 09:34:46 up 12 days, 21:57, 0 users, load average: 0.08, 0.09, 0.09 Server server2: 09:34:50 up 17 days, 2:30, 0 users, load average: 0.03, 0.03, 0.00 Server server3: 09:34:53 up 17 days, 2:31, 0 users, load average: 0.04, 0.04, 0.00
Dans cet exemple standard de bash pour boucle, nous allons mettre à jour tous les serveurs basés sur CentOS/RHEL en utilisant la commande yum ou la commande apt/apt-get dans le cas où nous avons des serveurs basés sur Debian/Ubuntu :
## CENTOS/RHEL example (for fedora replace yum with dnf) ## for s in server0{1..8} do echo "*** Patching and updating ${s} ***" ssh root@${s} -- "yum -y update" done
Voici un exemple de script shell simple mais utile :
#!/usr/bin/env bash # Purpose: Update all my Linode servers powered by Debian/Ubuntu Linux # Author: Vivek Gite under GPL v2.x+ # ---------------------------------------- log="/tmp/apt-get.log" >"${log}" for s in ln.cbz0{1..5} do echo "Updating and patching $s, please wait..." | tee -a "${log}" ssh root@${s} -- apt-get -q -y update >/dev/null ssh root@${s} -- DEBIAN_FRONTEND=noninteractive apt-get -y -q upgrade >>"${log}" done echo "Check $log file for details."
Voyez pourquoi nous avons utilisé la variable apt-get DEBIAN_FRONTEND pour éviter toute invite lors des mises à jour. Il serait préférable que vous configuriez des clés ssh à des fins d'automatisation ou pour exécuter des scripts à partir de tâches cron Linux/Unix.
Trouver le temps de ping pour plusieurs adresses IP
Voici mon exemple de code :
#!/bin/bash ips="$(host -t a www.cyberciti.biz | awk '{ print $4}')" for i in $ips; do ping -q -c 4 "$i"; done
Cela produira des statistiques moyennes comme suit, indiquant que le temps moyen d'ECHO_REQUEST ICMP de plusieurs équilibreurs de charge était de 19-20 millisecondes
PING 104.22.10.214 (104.22.10.214) 56(84) bytes of data. --- 104.22.10.214 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3006ms rtt min/avg/max/mdev = 20.612/21.255/22.054/0.624 ms PING 172.67.7.239 (172.67.7.239) 56(84) bytes of data. --- 172.67.7.239 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3005ms rtt min/avg/max/mdev = 19.199/20.279/21.433/0.862 ms PING 104.22.11.214 (104.22.11.214) 56(84) bytes of data. --- 104.22.11.214 ping statistics --- 4 packets transmitted, 4 received, 0% packet loss, time 3005ms rtt min/avg/max/mdev = 20.232/20.710/21.500/0.479 ms
Conclusion
Vous avez appris à utiliser la boucle for de bash avec divers exemples. Les boucles for peuvent vous faire gagner du temps et vous aider à automatiser de petites tâches. Cependant, pour les tâches complexes d'automatisation informatique, vous devez utiliser des outils comme Ansible, Salt, Chef, pssh et autres. Consultez les ressources suivantes pour plus d'informations.
- Voir tous les exemples de script shell en boucle dans notre répertoire bash shell.
- Page sur la syntaxe et l'utilisation de Bash pour les boucles, tirée du wiki sur les scripts shell de Linux.
- Lisez également les pages de manuel suivantes en utilisant la commande man ou la commande help :
$ man bash
$ help for
$ help {
$ help break
$ help continue