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.
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)
Merci pour ce billet, mais tu peux aussi forcer à rester dans le meme shell avec les parentheses :
exemple
i=0
ls -l | ( while read line; then
do
tab[$i]=$line
let i=i+1
done)
par contre, attention dans la suite, si tu fais un read !!!
A+
jean-philippe
Merci pour l’astuce Jean Philippe, j’essaierais Lundi ;)
Bon Week End ^^
let i=$i+1
Les 2 fonctionnent mon commandant ^^
Mais c’est vrai que c’est pas mal de rajouter cette manière de faire plus « conventionnelle » ;)