Bonjour tout le monde.
Un petit moment que je n’ai pas posté, et pour cause, je n’avais rien d’intéressant à dire… Je ne sais d’ailleurs pas si ce que je m’apprête à dire est réellement intéressant, mais si ca peut servir ne serait-ce qu’à une personne, je m’en satisferai.
On va parler de bash et de tableaux. J’ai récemment eu besoin d’utiliser les tableaux sous bash de façon peu conventionnelle. Par peu conventionnelle, j’entends « d’une façon que peu de personnes ont l’air d’utiliser » vu que je n’ai pas encore réussi à trouver ça sur le net. J’ai sûrement mal cherché… Bref, le but est de nommer son tableau avec une variable. Rendre variable le nom d’un tableau permet de faire des appels dynamiques à celui-ci (enfin ceux-ci). Comme je ne suis pas certain d’être parfaitement clair, on va illustrer le tout par des exemples. C’est parti.
1. Généralités
Commençons par quelques rappels sur les tableaux, surtout sur les différentes façons de les déclarer.
- On peut déclarer ligne par ligne
#!/bin/bash my_tab[0]="ligne1" my_tab[1]="ligne2" echo ${my_tab[0]} # affiche ligne1 echo ${my_tab[1]} # affiche ligne2
- Autre façon de déclarer ligne par ligne
#!/bin/bash my_tab=([0]="ligne1") my_tab=([1]="ligne2") echo ${my_tab[0]} # affiche ligne1 echo ${my_tab[1]} # affiche ligne2
- On peut déclarer plusieurs lignes en même temps
#!/bin/bash my_tab=([0]="ligne1" [1]="ligne2") # Pas de simples quotes, important pour plus tard echo ${my_tab[0]} # affiche ligne1 echo ${my_tab[1]} # affiche ligne2
- Autre façon de déclarer plusieurs lignes en même temps
#!/bin/bash my_tab=( ligne1 ligne2 ) # Pas de quotes non plus, important pour plus tard echo ${my_tab[0]} # affiche ligne1 echo ${my_tab[1]} # affiche ligne2
2. Utilisation des variables
Maintenant que l’on sait déclarer un tableau, comment peut-on utiliser une variable pour donner un nom au tableau ? De prime abord, on est tenté de se dire que c’est simple et qu’il suffit de mettre une variable dans le nom et de réutiliser cette même variable telle qu’elle. Sauf que non.
On veut créer un tableau différent pour chaque élément d’une liste. Voici quelques exemples qui ne marchent pas, juste pour la démonstration :
[pascal@localhost]> for TABVAR in $(echo tab1 tab2); do > mytab_$TABVAR[0]="ligne1" > mytab_$TABVAR[1]="ligne2" > done -bash: mytab_tab1[0]=ligne1: command not found -bash: mytab_tab2[1]=ligne1: command not found [pascal@localhost]> for TABVAR in $(echo tab1 tab2); do > mytab_${TABVAR}[0]="ligne1" > mytab_${TABVAR}[1]="ligne2" > done -bash: mytab_tab1[0]=ligne1: command not found -bash: mytab_tab2[1]=ligne1: command not found
La solution, c’est d’évaluer la déclaration de notre tableau :
[pascal@localhost]> for TABVAR in $(echo tab1 tab2); do > eval mytab_${TABVAR}[0]="ligne1" > eval mytab_${TABVAR}[1]="ligne2" > done [pascal@localhost]> echo ${mytab_tab1[0]} ligne1 [pascal@localhost]> echo ${mytab_tab1[1]} ligne2 [pascal@localhost]> echo ${mytab_tab2[0]} ligne1 [pascal@localhost]> echo ${mytab_tab2[1]} ligne2
On a donc maintenant 2 tableau de 2 lignes chacun : mytab_tab1 et mytab_tab2.
Toutes les affectations vues dans le premier paragraphe fonctionnent de la même façon (attention cependant, quelques petites différences, notamment au niveau de l’utilisation de simples quotes pour les affectaitions multiples) :
[pascal@localhost]> for TABVAR in $(echo tab1 tab2); do > eval mytab_${TABVAR}='( ligne1 ligne2 )' # Attention aux simples quotes qui sont obligatoires cette fois > done [pascal@localhost]> echo ${mytab_tab2[0]} ligne1 [pascal@localhost]> echo ${mytab_tab2[1]} ligne2 [pascal@localhost]> for TABVAR in $(echo tab1 tab2); do > eval mytab_${TABVAR}='([0]="ligne1" [1]="ligne2")' # Simples quotes obligatoires ici aussi > done [pascal@localhost]> echo ${mytab_tab2[0]} ligne1 [pascal@localhost]> echo ${mytab_tab2[1]} ligne2
Maintenant, voyons comment appeler l’un ou l’autre des 2 tableaux en fonction de la valeur de la variable TABVAR. Comme tout à l’heure, on commence par des exemples qui ne marchent pas :
[pascal@localhost]> TABVAR=tab1 [pascal@localhost]> echo ${mytab_$TABVAR[0]} -bash: ${mytab_$TABVAR[0]}: bad substitution [pascal@localhost]> echo ${mytab_${TABVAR}[0]} -bash: ${mytab_${TABVAR}[0]}: bad substitution
On y est presque, mais la solution est semblable à celle vu plus haut pour la déclaration de nos tableaux : il faut évaluer.
[pascal@localhost]> TABVAR=tab1 [pascal@localhost]> eval echo \${mytab_${TABVAR}[0]} ligne1
On peut maintenant s’amuser à changer les valeurs de TABVAR et les affectations, histoire de vérifier que ca fonctionne bien, par exemple :
[pascal@localhost]> TABVAR=supertablo [pascal@localhost]> eval mytab_${TABVAR}='( super genial top )' [pascal@localhost]> eval echo \${mytab_${TABVAR}[0]} super [pascal@localhost]> eval echo \${mytab_${TABVAR}[1]} genial [pascal@localhost]> eval echo \${mytab_${TABVAR}[2]} top
Je suis complètement conscient que mes exemples sont tout pourris, mais je ne doute pas une seconde que vous serez parfaitement à même de trouver une vraie utilité à ce petit article.
Je pense qu’il est bon d’ajouter qu’un tableau étant une variable comme une autre, ce que l’on vient de voir avec des tableaux fonctionne aussi parfaitement avec de simples variables, à quelques petites exceptions près. Un petit exemple pour la route :
#!/bin/bash VAR=youpi export myvar_${VAR}=coucou # créé la variable $myvar_youpi. # fonctionne aussi avec un eval comme pour les tableaux : # eval myvar_${VAR}=coucou echo $myvar_youpi # affiche coucou eval echo \$myvar_${VAR} # affiche coucou # On peut aussi ranger la variable dans une variable intermédiaire... var_temp=myvar_${VAR} # Puis afficher cette variable temporaire echo ${!var_temp} # affiche coucou. # accolades et point d'exclamation obligatoires sinon.... echo $var_temp # affiche myvar_youpi, c'est pas forcément ce qu'on veut.
Pour finir, lors de l’affectation de valeurs à un tableau ou à une variable avec un eval, il faudra bien penser à échapper les caractères habituellement interprétés par le shell, comme le point-virgule, les dollars etc… Voici l’erreur qui se produira si l’on oublie d’échapper ces caractères :
[pascal@localhost]> TABVAR=tab1 [pascal@localhost]> eval mytab_${TABVAR}[0]="coucou;hello" -bash: hello: command not found
Je me doute bien que vous savez pertinemment ce que signifie « échapper un caractère », mais je mets quand même la parade pour la forme :
[pascal@localhost]> TABVAR=tab1 [pascal@localhost]> eval mytab_${TABVAR}[0]="coucou\;hello" [oracle@deupacvm steps]$ eval echo \${mytab_${TABVAR}[0]} coucou
Bons développements à tous !