[shell] portée d'une variable dans une boucle while

Bonsoir,

Il y a un phénomène que je ne comprends pas à propos de la portée des variables. Dans le code suivant, les modifications faites sur les variables dans une boucle while sont perdues :

[code]#!/bin/sh

var=10

echo a | while read ligne; do
var=20
echo $var
done

echo $var[/code]

A l’exécution :

$ ./mystere.sh 20 10

Ce sont le pipe et le read qui provoquent ça mais pourquoi ?

Salut,

J’ai trouvé un sujet intéressant sur cette question. En fait, le pipe provoque la création d’un sous-shell qui va exécuter la boucle. Comme le processus fils est une copie du processus père, il n’influence pas les variables de ce dernier, ce qui explique pourquoi tu retrouves la valeur de 10 à la fin de la boucle :wink:

echo a | while read ligne; do

excuse moi mais il y a un truc que je ne comprend pas
Tu mets quoi dans la variable a?

Je pense que c’est un script d’exemple.

Il faut savoir que les | et & (ça n’est je pense pas le cas avec || et &&) créent un nouveau processus.

Pour une boucle qui lis un fichier ou l’entrée standard il vaut mieux utiliser read avec une redirection de flux < à la fin de la boucle.

Si c’est pour parser le contenu d’une variable (ce qui est le cas plus haut), il vaut mieux faire ça à la main en retouchant l’IFS par exemple.

@limax : c’est une chaîne de caractères toute simple : “a”.

Merci Taurre pour le coup de la variable $BASH_SUBSHELL qui indique le niveau d’imbrication des sous shells. Et effectivement, avec le pipe on travaille dans un sous shell.

Oui mais je voudrais plutôt faire un traitement ligne par ligne sur le résultat d’une commande.

Au final, j’ai trouvé une méthode qui permet de rediriger la sortie standard d’une commande vers l’entrée standard d’une autre commande, sans passer par le pipe, et donc sans créer un sous shell. C’est avec la syntaxe du here-document du shell.

D’abord on créé un fichier temporaire nommé tmp contenant ceci

abc def ghi jkl mno pqr ttt abc

Ensuite on exécute le script :

[code]#!/bin/sh

while read ligne; do
echo ligne $ligne
done <<delimiter
cat tmp | grep 'abc'
delimiter[/code]

Et voici le résultat :

$ ./script.sh ligne abc def ligne ttt abc

Merci de m’avoir aidé.