Les boucles de Bash – peuvent perdre le contenu de vos variables

Salut à tous,

 

J'en profite pour vous écrire ce billet, car je suis tombé sur un cas assez amusant ^^

J'avais à lister le contenu d'un répertoire, et à stocker chaque dossier / fichier dans un tableau ... (enfin je résume, car étant dans un contexte professionnel, je ne puis et vous le comprendrez aisément, vous donner le contexte précis :) )

 

D’où un simple :

 

i=0

ls  -l | while read line; then

do

tab[$i]=$line

let i=i+1

done

 

Malheureusement, lorsque vous essayez après cette boucle de récupérer le contenu d'un élément du tableau

 

echo ${tab[$i]}

 

Et bien vous n'aurez rien (ou alors le contenu de la variable précédemment initiée)
Bref pour rentrer un peu dans les explications, voici ce qui se passe vraiment :

Votre script s’exécute dans un environnement.
Mais dès lors que vous faites appel au "|" (pipe), vous rentrez dans un deuxième environnement.
Le premier environnement peut transmettre au deuxième environnement des informations, malheureusement, ça ne va pas dans les 2 sens.

 

160280

Avec le schéma ci-dessus, ça devrait être plus claire.
Le Shell peut transmettre des variables au sous Shell (via "export")
Néanmoins le sous-shell ne peut retourner au shell les variables modifiées.
Ainsi, le Shell initial ne tient pas compte des changements

 

Résultat des courses, vous pouvez dans ce cas là, chercher pendant des heures comment gérer ce genre de situation....

 

Solution simple : vous stocker dans des fichiers ..

Solution moyen simple, vous utilisez le EOF :) (End Of File)

EN gros :

i=0

res=$(ls -l)

while read line;

do

tab[$i]=$line

let line=line+1

done <<EOF
$res
EOF

En gros, vous passez toujours par un "sous-shell", mais uniquement pour le executer le "ls -l"

Le retour du ls -l, est ensuite renvoyé à la boucle qui se trouve bien dans le "shell" et donc

gère correctement les variables dans son environnement.

L'avantage en plus de cette solution est que vous pouvez réexploiter le retour du "ls" ( ou de la commande que vous voulez)

 

Ensuite il y a une autre manière de faire pas bien différente, mais je la met quand même :

 

i=0

while read line;

do

tab[$i]=$line

let line=line+1

done <  < (ls -l)

Partagez ce contenu

4 comments

Laisser une réponse

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *