GNU/Linux >> Tutoriels Linux >  >> Linux

Comment écrire une boucle dans Bash

Une raison courante pour laquelle les gens veulent apprendre le shell Unix est de débloquer la puissance du traitement par lots. Si vous souhaitez effectuer un ensemble d'actions sur de nombreux fichiers, l'une des façons de le faire est de construire une commande qui itère sur ces fichiers. Dans la terminologie de la programmation, cela s'appelle contrôle d'exécution, et l'un des exemples les plus courants est le for boucle.

Un pour loop est une recette détaillant les actions que vous voulez que votre ordinateur effectue pour chaque objet de données (tel qu'un fichier) que vous spécifiez.

La boucle for classique

Le Terminal Linux

  • Les 7 meilleurs émulateurs de terminaux pour Linux
  • 10 outils de ligne de commande pour l'analyse de données sous Linux
  • Télécharger maintenant :Aide-mémoire SSH
  • Aide-mémoire des commandes Linux avancées
  • Tutoriels de ligne de commande Linux

Une boucle facile à essayer est celle qui analyse une collection de fichiers. Ce n'est probablement pas une boucle utile en soi, mais c'est un moyen sûr de vous prouver que vous avez la capacité de gérer chaque fichier d'un répertoire individuellement. Tout d'abord, créez un environnement de test simple en créant un répertoire et en y plaçant des copies de certains fichiers. N'importe quel fichier fera l'affaire au départ, mais les exemples ultérieurs nécessitent des fichiers graphiques (tels que JPEG, PNG ou similaire). Vous pouvez créer le dossier et y copier des fichiers à l'aide d'un gestionnaire de fichiers ou dans le terminal :

Exemple de $ mkdir
        Exemple de $ cp ~/Pictures/vacation/*.{png,jpg}

Changez de répertoire pour votre nouveau dossier, puis répertoriez les fichiers qu'il contient pour confirmer que votre environnement de test correspond à ce que vous attendez :

exemple de $ cd
$ ls -1
cat.jpg
design_maori.png
otago.jpg
waterfall.png

La syntaxe pour parcourir chaque fichier individuellement dans une boucle est :créer une variable (f pour fichier, par exemple). Définissez ensuite l'ensemble de données que vous souhaitez que la variable parcourt. Dans ce cas, parcourez tous les fichiers du répertoire en cours à l'aide de * caractère générique (le * le caractère générique correspond à tout ). Terminez ensuite cette clause introductive par un point-virgule (; ).

$ for f in * ; 

Selon vos préférences, vous pouvez choisir d'appuyer sur Retour ici. Le shell n'essaiera pas d'exécuter la boucle tant qu'elle n'est pas terminée syntaxiquement.

Ensuite, définissez ce que vous voulez qu'il se passe à chaque itération de la boucle. Pour plus de simplicité, utilisez le fichier commande pour obtenir un peu de données sur chaque fichier, représenté par le f variable (mais précédée d'un $ pour dire au shell d'échanger la valeur de la variable pour tout ce que la variable contient actuellement) :

do file $f ; 

Terminez la clause par un autre point-virgule et fermez la boucle :

done 

Appuyez sur Retour pour démarrer le shell parcourant tout dans le répertoire courant. Le pour loop affecte chaque fichier, un par un, à la variable f et exécute votre commande :

$ pour f dans *; do
       > fichier $f;
       > done
        cat.jpg :données d'image JPEG, norme EXIF 2.2
        design_maori.png :données d'image PNG, 4 608 x 2 592, 8 bits /couleur RVB, non entrelacé
        otago.jpg :données d'image JPEG, norme EXIF ​​2.2
       waterfall.png :données d'image PNG, 4608 x 2592, 8 bits/couleur RVB, non entrelacé

Vous pouvez également l'écrire de cette façon :

$ pour f dans * ; faire fichier $f ; done
        cat.jpg :données d'image JPEG, norme EXIF 2.2
        design_maori.png :données d'image PNG, 4608 x 2592, RVB 8 bits/couleur, non entrelacé
        otago.jpg :Données d'image JPEG, norme EXIF ​​2.2
        waterfall.png :données d'image PNG, 4 608 x 2 592, RVB 8 bits/couleur, non entrelacé

Les formats multiligne et monoligne sont les mêmes pour votre shell et produisent exactement les mêmes résultats.

Un exemple pratique

Voici un exemple pratique de la façon dont une boucle peut être utile pour l'informatique de tous les jours. Supposons que vous ayez une collection de photos de vacances que vous souhaitez envoyer à vos amis. Vos fichiers photo sont volumineux, ce qui les rend trop volumineux pour être envoyés par e-mail et difficiles à télécharger sur votre service de partage de photos. Vous voulez créer des versions Web plus petites de vos photos, mais vous avez 100 photos et vous ne voulez pas passer du temps à réduire chaque photo, une par une.

Tout d'abord, installez ImageMagick commande à l'aide de votre gestionnaire de packages sous Linux, BSD ou Mac. Par exemple, sur Fedora et RHEL :

$ sudo dnf install ImageMagick 

Sur Ubuntu ou Debian :

$ sudo apt install ImageMagick 

Sur BSD, utilisez les ports ou pkgsrc. Sur Mac, utilisez Homebrew ou MacPorts.

Une fois que vous avez installé ImageMagick, vous disposez d'un ensemble de nouvelles commandes pour opérer sur les photos.

Créez un répertoire de destination pour les fichiers que vous êtes sur le point de créer :

$ mkdir tmp 

Pour réduire chaque photo à 33 % de sa taille d'origine, essayez cette boucle :

$ for f in * ; do convert $f -scale 33% tmp/$f ; done 

Ensuite, regardez dans le tmp dossier pour voir vos photos redimensionnées.

Vous pouvez utiliser n'importe quel nombre de commandes dans une boucle, donc si vous devez effectuer des actions complexes sur un lot de fichiers, vous pouvez placer l'ensemble de votre flux de travail entre le do et terminé déclarations d'un pour boucle. Par exemple, supposons que vous souhaitiez copier chaque photo traitée directement dans un répertoire de photos partagé sur votre hébergeur et supprimer le fichier photo de votre système local :

$ pour f dans *; do 
    convert $f -scale 33% tmp/$f
    scp -i seth_web tmp/$f [email protected]:~/public_html
    trash tmp/$f;
 fait

Pour chaque fichier traité par le for boucle, votre ordinateur exécute automatiquement trois commandes. Cela signifie que si vous traitez seulement 10 photos de cette façon, vous vous épargnez 30 commandes et probablement au moins autant de minutes.

Limiter votre boucle

Une boucle ne doit pas toujours regarder chaque fichier. Vous voudrez peut-être traiter uniquement les fichiers JPEG de votre répertoire d'exemple :

$ pour f dans *.jpg; convertissez $f -scale 33% tmp/$f; done
$ ls -m tmp
cat.jpg, otago.jpg

Ou, au lieu de traiter des fichiers, vous devrez peut-être répéter une action un certain nombre de fois. Un pour La variable de la boucle est définie par les données que vous lui fournissez, vous pouvez donc créer une boucle qui itère sur des nombres au lieu de fichiers :

$ pour n dans {0..4} ; faire echo $n; terminé
0
1
2
3
4

Plus de boucles

Vous en savez maintenant assez pour créer vos propres boucles. Jusqu'à ce que vous soyez à l'aise avec les boucles, utilisez-les sur des copies des fichiers que vous souhaitez traiter et, aussi souvent que possible, utilisez des commandes avec des protections intégrées pour vous empêcher de saboter vos données et de faire des erreurs irréparables, comme renommer accidentellement un répertoire entier de fichiers avec le même nom, chacun écrasant l'autre .

Pour pour avancé sujets en boucle, lisez la suite.

Tous les shells ne sont pas Bash

Le pour mot-clé est intégré au shell Bash. De nombreux shells similaires utilisent le même mot-clé et la même syntaxe, mais certains shells, comme tcsh, utilisent un mot-clé différent, comme foreach , à la place.

Dans tcsh, la syntaxe est similaire dans l'esprit mais plus stricte que Bash. Dans l'exemple de code suivant, ne tapez pas la chaîne foreach ? dans les lignes 2 et 3. Il s'agit d'une invite secondaire vous avertissant que vous êtes toujours en train de construire votre boucle.

$ foreach f (*)
foreach ? fichier $f
foreach ? fin
cat.jpg :données d'image JPEG, norme EXIF ​​2.2
design_maori.png :données d'image PNG, 4608 x 2592, RVB 8 bits/couleur, non entrelacé
otago.jpg :Données d'image JPEG, norme EXIF ​​2.2
waterfall.png :données d'image PNG, 4608 x 2592, RVB 8 bits/couleur, non entrelacé

Dans tcsh, les deux foreach et fin doit apparaître seul sur des lignes séparées, vous ne pouvez donc pas créer de for boucle sur une ligne comme vous pouvez le faire avec Bash et des shells similaires.

Boucles for avec la commande find

En théorie, vous pourriez trouver un shell qui ne fournit pas de for fonction de boucle, ou vous pouvez simplement préférer utiliser une commande différente avec des fonctionnalités supplémentaires.

La trouvaille La commande est une autre façon d'implémenter la fonctionnalité d'un for boucle, car elle offre plusieurs façons de définir la portée des fichiers à inclure dans votre boucle ainsi que des options de traitement parallèle.

La trouvaille La commande est destinée à vous aider à trouver des fichiers sur vos disques durs. Sa syntaxe est simple :vous fournissez le chemin de l'emplacement que vous souhaitez rechercher, et recherchez trouve tous les fichiers et répertoires :

$ trouver . 
.
./cat.jpg
./design_maori.png
./otago.jpg
./waterfall.png

Vous pouvez filtrer les résultats de la recherche en ajoutant une partie du nom :

$ trouver . -name "*jpg"
./cat.jpg
./otago.jpg

L'avantage de trouver est que chaque fichier qu'il trouve peut être introduit dans une boucle en utilisant le -exec drapeau. Par exemple, pour réduire uniquement les photos PNG de votre répertoire d'exemple :

$ trouver . -name "*png" -exec convert {} -scale 33% tmp/{} \;
$ ls -m tmp
design_maori.png, cascade.png

Dans le -exec clause, les crochets {} remplacer n'importe quel objet trouvé est en cours de traitement (en d'autres termes, tout fichier se terminant par PNG qui a été localisé, un par un). Le -exec La clause doit se terminer par un point-virgule, mais Bash essaie généralement d'utiliser le point-virgule pour lui-même. Vous "échappez" le point-virgule avec une barre oblique inverse (\; ) afin que trouve sait traiter ce point-virgule comme son caractère de fin.

La trouvaille commande est très bon dans ce qu'il fait, et il peut être trop bon parfois. Par exemple, si vous le réutilisez pour trouver des fichiers PNG pour un autre traitement photo, vous obtiendrez quelques erreurs :

$ trouver . -name "*png" -exec convert {} -flip -flop tmp/{} \; 
convert :impossible d'ouvrir l'image `tmp/./tmp/design_maori.png' :
Aucun fichier ou répertoire de ce type @ error/blob.c/OpenBlob/2643.
...

Il semble que trouver a localisé tous les fichiers PNG, pas seulement ceux de votre répertoire actuel (. ) mais aussi celles que vous avez traitées auparavant et placées dans votre tmp sous-répertoire. Dans certains cas, vous voudrez peut-être trouver pour rechercher le répertoire courant ainsi que tous les autres répertoires qu'il contient (et tous les répertoires de ceux ). Il peut s'agir d'un puissant outil de traitement récursif, en particulier dans les structures de fichiers complexes (comme les répertoires d'artistes musicaux contenant des répertoires d'albums remplis de fichiers musicaux), mais vous pouvez limiter cela avec le -maxdepth option.

Pour rechercher uniquement les fichiers PNG dans le répertoire courant (hors sous-répertoires) :

$ find . -maxdepth 1 -name "*png" 

Pour rechercher et traiter des fichiers dans le répertoire actuel plus un niveau supplémentaire de sous-répertoires, incrémentez la profondeur maximale de 1 :

$ find . -maxdepth 2 -name "*png" 

Sa valeur par défaut est de descendre dans tous les sous-répertoires.

En boucle pour le plaisir et le profit

Plus vous utilisez de boucles, plus vous économisez de temps et d'efforts, et plus les tâches que vous pouvez accomplir sont importantes. Vous n'êtes qu'un utilisateur, mais avec une boucle bien pensée, vous pouvez faire en sorte que votre ordinateur fasse le gros du travail.

Vous pouvez et devez traiter la boucle comme n'importe quelle autre commande, en la gardant à portée de main lorsque vous devez répéter une ou deux actions sur plusieurs fichiers. Cependant, c'est aussi une passerelle légitime vers une programmation sérieuse, donc si vous devez accomplir une tâche complexe sur un nombre quelconque de fichiers, prenez un moment de votre journée pour planifier votre flux de travail. Si vous pouvez atteindre votre objectif sur un seul fichier, alors encapsulez ce processus reproductible dans un for loop est relativement simple, et la seule "programmation" requise est une compréhension du fonctionnement des variables et une organisation suffisante pour séparer les fichiers non traités des fichiers traités. Avec un peu de pratique, vous pouvez passer d'un utilisateur Linux à un utilisateur Linux qui sait comment écrire une boucle, alors lancez-vous et faites fonctionner votre ordinateur pour vous !


Linux
  1. Comment utiliser les commandes d'historique de Bash

  2. Comment déboguer un script bash ?

  3. Comment arrêter le script Loop Bash dans le terminal ?

  4. Comment détecter Bash>=4.0 ?

  5. Comment écrire une chaîne de plusieurs lignes en utilisant Bash avec des variables ?

Bash pendant la boucle

Bash pour la boucle

Bash jusqu'à la boucle

Script bash :comment écrire des données dans des fichiers texte

Shell Scripting pour les débutants - Comment écrire des scripts Bash sous Linux

Comment exécuter un script bash