GNU/Linux >> Tutoriels Linux >  >> Linux

Introduction à la programmation Linux Bash :5 astuces pour la boucle "for"

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.


Linux
  1. Comment écrire une boucle dans Bash

  2. Hivériser votre invite Bash sous Linux

  3. Langage de programmation C - Introduction

  4. Script Linux :3 tutoriels pour les boucles while dans Bash

  5. 12 exemples de boucle Bash For pour votre script de shell Linux

Bash pour la boucle

Bash jusqu'à la boucle

Commande d'historique sous Linux (historique de bash)

Une introduction au navigateur Vivaldi sous Linux

5 conseils pour maîtriser Linux

20 conseils de programmation Killer Perl pour les débutants sur UNIX / Linux OS