2.6. Indirection

Bash offre deux moyens pour obtenir la valeur d'une variable v1 dont le nom est accessible via une autre variable var : l'indirection par substitution et les variables nameref. Ces mécanismes, appelés indirections, permettent d'accéder de manière indirecte et pa conséquent de façon plus souple, à la valeur d'un deuxième objet.

2.6.1. Indirection par substitution

On utilise la syntaxe de substitution suivante : ${!var}.

$ var=v1
$ v1=un
$ 
$ echo ${!var}
un
$

La variable var a pour valeur la chaine v1. Celle-ci correspond au nom d'une deuxième variable ayant pour valeur la chaine un. La syntaxe ${!var} permet d'accéder indirectement à la valeur de la variable v1.

Le fichier shell indir illustre la souplesse des indirections en montrant comment il est possible de créer « à la volée » le nom de la variable qui contient l’information souhaitée.

	#!/bin/bash
	#	@(#)	indir

	agePierre=10
	ageJean=20

	read -p "Quel age (Pierre ou Jean) voulez-vous connaitre ? "  prenom

	rep=age$prenom		# construction du nom de la variable
	echo ${!rep}

Deux variables agePierre et ageJean contiennent respectivement l’âge des personnes Pierre et Jean. Le programme demande à l’utilisateur de saisir le prénom dont il souhaite connaître l’âge, construit le nom de la variable contenant l’âge demandé puis affiche ce dernier.

$ indir
Quel age (Pierre ou Jean) voulez-vous connaitre ? Pierre
10
$ 
$ indir 
Quel age (Pierre ou Jean) voulez-vous connaitre ? Jean
20
$

Ce mécanisme s’applique également aux deux autres types de paramètres : les paramètres de position et les paramètres spéciaux.

$ x=un
$ b=deux
$ c=trois
$ 
$ set x b c		=>  $1, $2 et $3 ont respectivement pour valeur les chaînes
$			=>    "x", "b", "c"
$ echo $2
b
$
$ echo ${!2}	=> la valeur de $2 est la chaîne "b" qui est le nom d’une variable
deux		=>    contenant la valeur "deux"
$
$ echo ${!3}
trois
$
$ echo ${!#}	=> la valeur de $# est 3 et la valeur de $3 est la chaîne "c"
c
$

Remarque :

il ne faut pas confondre deux syntaxes très proches fournies par bash mais qui correspondent à deux mécanismes totalement différents : ${!param} et ${!var*}

La première syntaxe sera interprétée par le shell comme une indirection, tandis que la deuxième sera remplacée par les noms de variables qui commencent par var.

$ A=alpha
$ x=beta
$ Age=20
$ 
$ echo ${!A*}	=> ${!A*} sera remplacée par les noms de 
A Age 		=>    variables qui commencent par A
$

2.6.2. Variables nameref

Une variable nameref var contient une référence à une autre variable v.

Pour définir une variable nameref on peut utiliser la syntaxe suivante : declare -n var[=v].

$ declare -n var1=v2
$ declare -p var1
declare -n var1="v2"
$ 
$ v2=bonjour
$ 
$ echo $var1
bonjour			=> valeur de la variable v2
$ 
$ v2=hello
$ 
$ echo $var1
hello
$

Contrairement aux indirections par substitution, après initialisation d'une variable nameref, on ne peut modifier la référence qu'elle contient (à moins de redéfinir la variable nameref).

$ v3="au revoir"
$ var1=v3
$ echo $var1
v3				=> affichage du nom de la variable (v3) et non de sa valeur (au revoir)
$ 
$ declare -n var1=v3		=> redéfinition de var1
$ echo $var1 
au revoir 			=> affichage correct de la valeur de la variable v3
$

Le mécanisme nameref est généralement utilisé par une fonction pour modifier la valeur d'une variable qui lui est extérieure et qui lui a été transmise en argument [cf. Chapitre 14, Fonctions shell].