web-dev-qa-db-fra.com

Comment canaliser l'entrée vers une boucle while et conserver les variables après la fin de la boucle

Bash permet d'utiliser: cat <(echo "$FILECONTENT")

Bash permet également d'utiliser: while read i; do echo $i; done </etc/passwd

pour combiner les deux précédents, cela peut être utilisé: echo $FILECONTENT | while read i; do echo $i; done

Le dernier problème est qu’il crée un sous-shell et qu’après la fin de la boucle while, la variable i n’est plus accessible.

Ma question est:

Comment réaliser quelque chose comme ceci: while read i; do echo $i; done <(echo "$FILECONTENT") ou en d'autres termes: comment puis-je être sûr que i survit en boucle?

Veuillez noter que je suis conscient de l'inclusion de l'instruction while dans {}, Mais cela ne résout pas le problème (imaginez que vous souhaitiez utiliser la boucle while dans la fonction et renvoyer la variable i.)

71
Wakan Tanka

La notation correcte pour Process Substitution est:

while read i; do echo $i; done < <(echo "$FILECONTENT")

La dernière valeur de i attribuée dans la boucle est alors disponible à la fin de la boucle. Une alternative est:

echo $FILECONTENT | 
{
while read i; do echo $i; done
...do other things using $i here...
}

Les accolades sont une opération de regroupement d'E/S et ne créent pas elles-mêmes un sous-shell. Dans ce contexte, ils font partie d’un pipeline et sont donc gérés en tant que sous-shell, mais c’est à cause de la |, pas le { ... }. Vous en parlez dans la question. Autant que je sache, vous pouvez faire un retour de l'intérieur dans une fonction.


Bash fournit également le shopt intégré et l’une de ses nombreuses options est:

lastpipe

Si cette option est définie et que le contrôle des travaux n’est pas actif, le Shell exécute la dernière commande d’un pipeline non exécutée en arrière-plan dans l’environnement Shell en cours.

Ainsi, en utilisant quelque chose comme ceci dans un script , le modfié sum disponible après la boucle:

FILECONTENT="12 Name
13 Number
14 Information"
shopt -s lastpipe   # Comment this out to see the alternative behaviour
sum=0
echo "$FILECONTENT" |
while read number name; do ((sum+=$number)); done
echo $sum

Faire cela sur la ligne de commande est généralement considéré comme "le contrôle des tâches n’est pas actif" (c’est-à-dire que le contrôle des tâches est actif). Tester ceci sans utiliser de script a échoué.

En outre, comme indiqué par Gareth Rees dans son réponse , vous pouvez parfois utiliser un ici chaîne :

while read i; do echo $i; done <<< "$FILECONTENT"

Cela ne nécessite pas shopt; vous pourrez peut-être enregistrer un processus en l'utilisant.

92
Jonathan Leffler

Jonathan Leffler explique comment faire ce que vous voulez en utilisant processus de substitution , mais une autre possibilité est de utilisez un ici chaîne :

while read i; do echo "$i"; done <<<"$FILECONTENT"

Cela enregistre un processus.

26
Gareth Rees