Peut-être connaissez vous déjà la syntaxe suivante :

while read arg1 arg2 arg3; do
       echo $arg3 $arg2 $arg1
   done < mon_fichier.txt

Qui consiste à prendre le  contenu d'un fichier (ici mon_fichier.txt) et de le donner "à manger" (d'où le <) à la "combinaison" while + read :
* read permettant d'affecter tous les éléments trouvés sur une ligne à des variables (ici arg1, arg2 et arg3)
* while à exécutant le code qui le suit (ici le echo ... présent en deuxième ligne) pour chaque ligne du fichier donné en entrée.
En gros ce "combo" permet en général de parcourir un fichier.

En exécutant le code ci-dessus avec un fichier texte contenant 3 mots par ligne on obtient en sortie pour chaque ligne les 3 mots en ordre inverse.

 


On peut très bien écrire la même chose d'une manière différente :

cat mon_fichier.txt | while read arg1 arg2 arg3; do
       echo $arg3 $arg2 $arg1
   done

Ici on passe par l'utilisation d'un | (appelé pipe, tuyau en anglais) ; le résulat de ce qui est exécuté à gauche du pipe est utilisé en entrée par le bout de code à droite du pipe (à la manière du < du premier exemple).

Cette syntaxe possède bien des avantages :
* Elle est plus lisible : on commence par le début. D'autant plus si le code exécuté dans la boucle while ... done est long (plusieurs dizaines de ligne).
* Mais le plus important : vu que l'on utilise un pipe, pas besoin de se limiter au contenu d'un fichier (comme dans le cas 1) on peut donner à manger à while read n'importe quel type de contenu (parcourir le résultat d'un "du -sh", d'un "iptables", ou même d'une variable contenant elle même plusieurs lignes, etc.)

Il serait tentant de privilégier cette syntaxe oui mais voilà elle possède un problème de taille : son pipe.
Le problème du pipe est qu'un sous-shell va être lancé pour exécuter le code... et dans ce genre de cas à la fin de cette exécution les variables qui auraient pu être affectées vont être perdues. On se retrouve donc avec un souci ressemblant fort à un problème de portée de variable. C'est un piège classique mais qui surprend quand on voit que le code a bien été exécuter mais que les variables restent inchangées après le passage dans le "pipe while read".

Il faut donc privilégier cette syntaxe uniquement s'il n'y a pas d'affectation de variable ou que celle-ci doit rester locale (utilisation du résultat dans la boucle). Par exemple pour faire de l'affichage comme dans notre code ou pour utiliser des variables définies avant... pas de problème. En revanche récupérer une valeur dans la boucle pour la réexploiter après n'est pas possible avec cette syntaxe là.
Donc à retenir ce qui est affecté avant reste utilisable dans la boucle mais ce qui est affecté dans la boucle ne l'est plus utilisable après.


Tout ceci est très bien mais nous avons quand même vu un gros avantage au "pipe while read" : le fait de pouvoir donner tout type de contenu "à manger" à notre boucle.

Il existe en réalité une syntaxe qui marche en Bash (pas en sh de base par contre) et qui se veut un peu être le meilleur des deux mondes (sans la partie "un peu plus lisible" du 2ème cas, il est vrai). Alors certes elle est un peu tordue mais elle est efficace !
En réalité il suffit d'utiliser la première syntaxe en remplaçant le nom du fichier par l'exécution du commande grâce aux caractères "<( ... )" :

while read arg1 arg2 arg3; do
       echo $arg3 $arg2 $arg1
   done < <( cat mon_fichier.txt )

... revient au même que le cas 1 sauf que l'on peut remplacer "cat mon_fichier.txt" par tout autre commande comme le permettait le cas 2 sans le problème posé par ce dernier (portée de variable).

En bref s'il n'y a aucune raison de récupérer des valeurs dans la boucle pour les réafficher après (typiquement utiliser une boucle pour faire de l'affichage) autant utiliser le cas 2 pour plus de lisibilité. Dès lors qu'il y a besoin de récupérer des valeurs dans la boucle utiliser le cas 1 si on ne traite que la lecture d'un fichier et de manière universelle utiliser le cas 3 (mon petit chouchou).

 
Tag(s) : #bash

Partager cet article

Repost 0
Pour être informé des derniers articles, inscrivez vous :