Chaque administrateur système possède probablement une compétence qu'il a acquise au fil des ans et qu'il peut pointer du doigt et dire :"Cela a changé mon monde". Cette compétence, ou cette information, ou cette technique a juste changé ma façon de faire les choses. Pour beaucoup d'entre nous, cette chose est en train de boucler à Bash. Il existe d'autres approches de l'automatisation qui sont certainement plus robustes ou évolutives. La plupart d'entre eux ne se comparent pas à la simplicité et à la facilité d'utilisation du for
boucle, cependant.
Si vous souhaitez automatiser la configuration de milliers de systèmes, vous devriez probablement utiliser Ansible. Cependant, si vous essayez de renommer un millier de fichiers ou d'exécuter la même commande plusieurs fois, alors le for
loop est définitivement le bon outil pour le travail.
[ Vous pourriez également aimer : Maîtriser les boucles avec les modèles Jinja dans Ansible ]
Si vous avez déjà une formation en programmation ou en script, vous savez probablement à quoi for
les boucles font. Si ce n'est pas le cas, j'essaierai de le décomposer en langage clair pour vous.
Le concept de base est :POUR un ensemble donné d'éléments, DO une chose.
L'ensemble d'éléments donné peut être un ensemble littéral d'objets ou tout ce que Bash peut extrapoler à une liste. Par exemple, du texte extrait d'un fichier, la sortie d'une autre commande Bash ou des paramètres transmis via la ligne de commande. La conversion de cette structure de boucle en un script Bash est également triviale. Dans cet article, nous vous montrons quelques exemples de la façon dont un for
loop peut vous faire ressembler à un héros de la ligne de commande, puis nous prenons certains de ces exemples et les plaçons dans un script Bash plus structuré.
Structure de base de la boucle for
Tout d'abord, parlons de la structure de base d'un for
boucle, puis nous aborderons quelques exemples.
La syntaxe de base d'un for
boucle est :
for <variable name> in <a list of items>;do <some command> $<variable name>;done;
Le nom de la variable sera la variable que vous spécifiez dans le do
et contiendra l'élément de la boucle sur laquelle vous vous trouvez.
La liste des éléments peut être tout ce qui renvoie un espace ou une liste séparée par des retours à la ligne.
Voici un exemple :
$ for name in joey suzy bobby;do echo $name;done
C'est à peu près aussi simple que possible et il ne se passe pas grand-chose là-bas, mais cela vous permet de démarrer. La variable $name contiendra l'élément de la liste sur lequel la boucle opère actuellement, et une fois la commande (ou les commandes) dans le do
section sont effectuées, la boucle passera à l'élément suivant. Vous pouvez également effectuer plusieurs actions par boucle. N'importe quoi entre do
et done
sera exécuté. Les nouvelles commandes ont juste besoin d'un ;
les délimitant.
$ for name in joey suzy bobby; do echo first $name;echo second $name;done;
first joey
second joey
first suzy
second suzy
first bobby
second bobby
Maintenant, pour du vrai exemples.
Renommer des fichiers
Cette boucle prend la sortie de la commande Bash ls *.pdf
et effectue une action sur chaque nom de fichier renvoyé. Dans ce cas, nous ajoutons la date d'aujourd'hui à la fin du nom de fichier (mais avant l'extension de fichier).
for i in $(ls *.pdf); do
mv $i $(basename $i .pdf)_$(date +%Y%m%d).pdf
done
Pour illustrer, exécutez cette boucle dans un répertoire contenant ces fichiers :
file1.pdf
file2.pdf
...
fileN.pdf
Les fichiers seront renommés comme ceci :
file1_20210210.pdf
file2_20210210.pdf
...
fileN_20210210.pdf
Dans un répertoire contenant des centaines de fichiers, cette boucle vous fait gagner un temps considérable en les renommant tous.
Extrapolation des listes d'éléments
Imaginez que vous avez un fichier que vous voulez scp
à plusieurs serveurs. N'oubliez pas que vous pouvez combiner le for
boucle avec d'autres fonctionnalités de Bash, telles que l'expansion du shell, qui permet à Bash d'étendre une liste d'éléments qui font partie d'une série. Cela peut fonctionner pour les lettres et les chiffres. Par exemple :
$ echo {0..10}
0 1 2 3 4 5 6 7 8 9 10
En supposant que vos serveurs sont nommés dans une sorte de modèle comme, web0 , web1 , web2 , web3 , vous pouvez demander à Bash d'itérer la série de nombres comme ceci :
$ for i in web{0..10};do scp somefile.txt ${i}:;done;
Cela va parcourir web0 , web1 , web2 , web3 , et ainsi de suite, en exécutant votre commande sur chaque élément.
Vous pouvez également définir quelques itérations. Par exemple :
$ for i in web{0..10} db{0..2} balance_{a..c};do echo $i;done
web0
web1
web2
web3
web4
web5
web6
web7
web8
web9
web10
db0
db1
db2
balance_a
balance_b
balance_c
Vous pouvez également combiner des itérations. Imaginez que vous avez deux centres de données, l'un aux États-Unis, l'autre au Canada, et que la convention de dénomination du serveur identifie le centre de données dans lequel une paire de serveurs HA réside. Par exemple, web-us-0 serait le premier serveur Web du centre de données américain, tandis que web-ca-0 seraient des web 0 homologue dans le centre de données CA. Pour exécuter quelque chose sur les deux systèmes, vous pouvez utiliser une séquence comme celle-ci :
$ for i in web-{us,ca}-{0..3};do echo $i;done
web-us-0
web-us-1
web-us-2
web-us-3
web-ca-0
web-ca-1
web-ca-2
web-ca-3
Dans le cas où vos noms de serveur ne sont pas faciles à parcourir, vous pouvez fournir une liste de noms au for
boucle :
$ cat somelist
first_item
middle_things
foo
bar
baz
last_item
$ for i in `cat somelist`;do echo "ITEM: $i";done
ITEM: first_item
ITEM: middle_things
ITEM: foo
ITEM: bar
ITEM: baz
ITEM: last_item
Imbrication
Vous pouvez également combiner certaines de ces idées pour des cas d'utilisation plus complexes. Par exemple, imaginez que vous vouliez copier une liste de fichiers sur vos serveurs Web qui suivent la convention de dénomination numérotée que vous avez utilisée dans l'exemple précédent.
Vous pouvez y parvenir en itérant une deuxième liste basée sur votre première liste via des boucles imbriquées. Cela devient un peu difficile à suivre lorsque vous le faites en une seule ligne, mais cela peut certainement être fait. Votre for
imbriqué la boucle est exécutée à chaque itération du parent for
boucle. Assurez-vous de spécifier des noms de variables différents pour chaque boucle.
Pour copier la liste des fichiers file1.txt, file2.txt, et fichier3.txt aux serveurs Web, utilisez cette boucle imbriquée :
$ for i in file{1..3};do for x in web{0..3};do echo "Copying $i to server $x"; scp $i $x; done; done
Copying file1 to server web0
Copying file1 to server web1
Copying file1 to server web2
Copying file1 to server web3
Copying file2 to server web0
Copying file2 to server web1
Copying file2 to server web2
Copying file2 to server web3
Copying file3 to server web0
Copying file3 to server web1
Copying file3 to server web2
Copying file3 to server web3
Renommage plus créatif
Il peut y avoir d'autres façons d'y parvenir, mais rappelez-vous, ce n'est qu'un exemple de choses que vous pouvez faire avec un for
boucle. Que faire si vous avez une montagne de fichiers nommés quelque chose comme FILE002.txt , et vous souhaitez remplacer FILE avec quelque chose comme TEXTE . N'oubliez pas qu'en plus de Bash lui-même, vous avez également d'autres outils open source à votre disposition, comme sed
, grep
, et plus. Vous pouvez combiner ces outils avec le for
boucle, comme ceci :
$ ls FILE*.txt
FILE0.txt FILE10.txt FILE1.txt FILE2.txt FILE3.txt FILE4.txt FILE5.txt FILE6.txt FILE7.txt FILE8.txt FILE9.txt
$ for i in $(ls FILE*.txt);do mv $i `echo $i | sed s/FILE/TEXT/`;done
$ ls FILE*.txt
ls: cannot access 'FILE*.txt': No such file or directory
$ ls TEXT*.txt
TEXT0.txt TEXT10.txt TEXT1.txt TEXT2.txt TEXT3.txt TEXT4.txt TEXT5.txt TEXT6.txt TEXT7.txt TEXT8.txt TEXT9.txt
Ajouter une boucle for à un script Bash
Exécution de for
boucles directement sur la ligne de commande est génial et vous fait gagner un temps considérable pour certaines tâches. De plus, vous pouvez inclure for
boucles dans le cadre de vos scripts Bash pour une puissance, une lisibilité et une flexibilité accrues.
Par exemple, vous pouvez ajouter l'exemple de boucle imbriquée à un script Bash pour améliorer sa lisibilité, comme ceci :
$ vim copy_web_files.sh
# !/bin/bash
for i in file{1..3};do
for x in web{0..3};do
echo "Copying $i to server $x"
scp $i $x
done
done
Lorsque vous enregistrez et exécutez ce script, le résultat est le même que l'exécution de l'exemple de boucle imbriquée ci-dessus, mais il est plus lisible et plus facile à modifier et à entretenir.
$ bash copy_web_files.sh
Copying file1 to server web0
Copying file1 to server web1
... TRUNCATED ...
Copying file3 to server web3
Vous pouvez également augmenter la flexibilité et la réutilisabilité de votre for
boucles en les incluant dans des scripts Bash qui permettent la saisie de paramètres. Par exemple, pour renommer des fichiers comme dans l'exemple Plus de renommage créatif ci-dessus permettant à l'utilisateur de spécifier le suffixe du nom, utilisez ce script :
$ vim rename_files.sh
# !/bin/bash
source_prefix=$1
suffix=$2
destination_prefix=$3
for i in $(ls ${source_prefix}*.${suffix});do
mv $i $(echo $i | sed s/${source_prefix}/${destination_prefix}/)
done
Dans ce script, l'utilisateur fournit le préfixe du fichier source comme premier paramètre, le suffixe du fichier comme deuxième et le nouveau préfixe comme troisième paramètre. Par exemple, pour renommer tous les fichiers commençant par FILE , de type .txt au TEXTE , exécutez le script comme ceci :
$ ls FILE*.txt
FILE0.txt FILE10.txt FILE1.txt FILE2.txt FILE3.txt FILE4.txt FILE5.txt FILE6.txt FILE7.txt FILE8.txt FILE9.txt
$ bash rename_files.sh FILE txt TEXT
$ ls TEXT*.txt
TEXT0.txt TEXT10.txt TEXT1.txt TEXT2.txt TEXT3.txt TEXT4.txt TEXT5.txt TEXT6.txt TEXT7.txt TEXT8.txt TEXT9.txt
Ceci est similaire à l'exemple d'origine, mais vos utilisateurs peuvent désormais spécifier d'autres paramètres pour modifier le comportement du script. Par exemple, pour renommer tous les fichiers commençant maintenant par TEXT à NOUVEAU , utilisez ce qui suit :
$ bash rename_files.sh TEXT txt NEW
$ ls NEW*.txt
NEW0.txt NEW10.txt NEW1.txt NEW2.txt NEW3.txt NEW4.txt NEW5.txt NEW6.txt NEW7.txt NEW8.txt NEW9.txt
[ Un cours gratuit pour vous :présentation technique de la virtualisation et de la migration d'infrastructure. ]
Conclusion
Espérons que ces exemples ont démontré la puissance d'un for
boucle sur la ligne de commande Bash. Vous pouvez vraiment gagner beaucoup de temps et effectuer des tâches de manière moins sujette aux erreurs avec des boucles. Fais attention. Vos boucles feront ce que vous leur demandez, même si vous leur demandez de faire quelque chose de destructeur par accident, comme créer (ou supprimer) des volumes logiques ou des disques virtuels.
Nous espérons que Bash for
les boucles changent votre monde de la même manière qu'elles ont changé le nôtre.