Utiliser «While read…» dans un script Linux

34

Quelqu'un pourrait-il s'il vous plaît expliquer comment le code suivant fonctionne?

echo '1 2 3 4 5 6' | while read a b c
do
  echo $c $b $a
done

Plus précisément, j'aimerais savoir pourquoi la sortie de cette boucle est 3 4 5 6 2 1au lieu de 3 2 1et 6 5 4sur deux lignes distinctes? Je n'arrive pas à penser à cela…

linuxgringo
la source

Réponses:

41

readlit une ligne entière à partir de l'entrée standard, la divise en champs et assigne ces champs aux variables données. S'il y a plus de pièces que de variables, les pièces restantes sont affectées à la dernière variable.

Dans votre cas $aest assigné 1, $best assigné 2et $cle reste 3 4 5 6.

Florian Diesch
la source
Merci Florian! Maintenant, cela a du sens ... Pour une raison quelconque, je pensais que les espaces délimiteraient chaque lecture de variable, mais apparemment pas. J'apprécie ton aide!!
linuxgringo
24

Réécrire la boucle de cette façon révèle ce qui se passe:

echo '1 2 3 4 5 6' | while read a b c
  do
    echo '(iteration beginning)' a="$a" b="$b" c="$c" '(iteration ending)'
  done

Cela donne, en sortie:

(iteration beginning) a=1 b=2 c=3 4 5 6 (iteration ending)

Notez tout d’abord que seule une commande echo est exécutée. S'il était exécuté plus d'une fois, vous verriez entre autres le (iteration beginning)et les (iteration ending)sous - chaînes imprimées plus d'une fois.

Cela revient à dire qu'avoir une whileboucle ici n'apporte vraiment rien. La fonction readintégrée lit le texte 1 séparé par des espaces dans chaque variable spécifiée. Une entrée supplémentaire est ajoutée à la fin de la dernière variable spécifiée. 2 Ainsi, les variables aet bprennent les valeurs 1et 2respectivement, tandis que cprend la valeur 3 4 5 6.

Lorsque la condition de boucle ( while read a b c) est évaluée pour la deuxième fois, il n’ya plus d’entrée disponible dans le tube (nous lui avons simplement acheminé une seule ligne de texte). La readcommande est donc évaluée à false au lieu de true et la boucle s’arrête corps une seconde fois).

1 : Pour être technique et spécifique, la commande readintégrée , lorsqu'elle transmet des noms de variable en tant qu'arguments, lit les entrées en les séparant en "mots" distincts lorsqu'elle rencontre des espaces IFS (voir aussi cette question et cet article ).

readLe comportement de 2 : le fait de coincer tout champ supplémentaire d’entrée dans la dernière variable spécifiée est peu intuitif pour beaucoup de scripteurs, au début. Il devient plus facile de comprendre quand on considère que, comme le dit la réponse de Florian Diesch , on readva toujours (essayer de) lire toute une ligne - et cela readdoit être utilisable à la fois avec et sans boucle.

Eliah Kagan
la source
Eliah, merci d'avoir pris le temps d'expliquer tous les détails. Je soupçonnais que whilecela ne servait pas son objectif habituel dans cet exemple, mais ensuite la readcommande m'a renvoyé ... D'une manière ou d'une autre, je l'ai interprété comme "tant que ce read a b cn'est pas faux, fais echo ...". Merci d'avoir expliqué comment cela fonctionnait vraiment. Je suis tombé sur ce code hier et je savais que cela m'ennuierait jusqu'à ce que je le découvre ... lol
linuxgringo
@linuxgringo En réalité, le corps de la boucle est exécuté chaque fois que la valeur est read a b cvraie et la condition de la boucle ( read a b c) s'exécute plus d'une fois. Bit, il s’évalue seulement à vrai la 1ère fois. Pour la deuxième fois, il n'y a plus d'entrées à lire dans le canal, ce qui provoque la fin du fichierread et renvoie false . ( help readPour plus de détails, reportez-vous à la dernière section de la sortie de "État de sortie", en notant que, dans les scripts shell, zéro signifie vrai et non nul veut dire faux.) Si vous transmettez plus d'une ligne d'entrée while read ..., le corps de la boucle être exécuté plusieurs fois.
Eliah Kagan