Chapitre 2. Substitution de paramètres

Table des matières

2.1. Variables
2.1.1. Affectation
2.1.2. Variable en « lecture seule »
2.1.3. Variables d'environnement
2.2. Paramètres de position et paramètres spéciaux
2.2.1. Paramètres de position
2.2.2. Paramètres spéciaux
2.2.3. Commande interne shift
2.2.4. Paramètres de position et fichiers shell
2.2.5. Paramètres spéciaux * et @
2.3. Suppression des ambiguïtés
2.4. Paramètres non définis
2.5. Suppression de variables
2.6. Indirection
2.6.1. Indirection par substitution
2.6.2. Variables nameref

Dans la terminologie du shell, un paramètre désigne toute entité pouvant contenir une valeur.

Le shell distingue trois classes de paramètres :

  • les variables, identifiées par un nom (ex : a , PATH)

  • les paramètres de position, identifiés par un numéro (ex : 0 , 1 , 12)

  • les paramètres spéciaux, identifiés par un caractère spécial (ex : # , ? , $)

Le mode d’affectation d'une valeur est spécifique à chaque classe de paramètres. Suivant celle-ci, l’affectation sera effectuée par l’utilisateur, par bash ou bien par le système. Par contre, pour obtenir la valeur d'un paramètre, on placera toujours le caractère $ devant sa référence, et cela quelle que soit sa classe.

$ echo $PATH  		=> affiche la valeur de la variable PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:. 
$ echo $$ 		=> affiche la valeur du paramètre spécial $
17286
$

2.1. Variables

Une variable est identifiée par un nom, c'est-à-dire une suite de lettres, de chiffres ou de caractères espace souligné ne commençant pas par un chiffre. Les lettres majuscules et minuscules sont différenciées.

Les variables peuvent être classées en trois groupes :

  • les variables utilisateur (ex : a, valeur)

  • les variables prédéfinies du shell (ex : PS1, PATH, REPLY, IFS)

  • les variables prédéfinies de commandes unix (ex : TERM).

En général, les noms des variables utilisateur sont en lettres minuscules tandis que les noms des variables prédéfinies (du shell ou de commandes unix) sont en majuscules.

L’utilisateur peut affecter une valeur à une variable en utilisant l’opérateur d’affectation = ou la commande interne read.

2.1.1. Affectation

  1. Affectation directe

    Syntaxe : nom=[valeur] [ nom=[valeur] ... ]

    Il est impératif que le nom de la variable, le symbole = et la valeur à affecter ne forment qu’une seule chaîne de caractères.

    Plusieurs affectations peuvent être présentes dans la même ligne de commande.

    $ x=coucou  y=bonjour 		=> la variable x contient la chaîne de caractères coucou
    $ 				=> la variable y contient la chaîne bonjour
    

    ATTENTION : les syntaxes d’affectation erronées les plus fréquentes contiennent :

    • un ou plusieurs caractères espace entre le nom de la variable et le symbole =.

      $ b =coucou
      bash: b : commande introuvable
      $
      

      Le shell interprète b comme une commande à exécuter ; ne la trouvant pas, il signale une erreur.

    • un ou plusieurs caractères espace entre le symbole = et la valeur de la variable.

      $ z= coucou
      bash: coucou : commande introuvable
      $
      

      La chaîne coucou est interprétée comme la commande à exécuter.

    Lorsque le shell rencontre la chaîne $x, il la remplace textuellement par la valeur de la variable x, c.-à-d. coucou ; en d'autres termes, la chaîne $x est remplacée par la chaîne coucou. Dans l'exemple ci-dessous, la commande finalement exécutée par bash est : echo x est coucou

    $ echo x est $x
    x est coucou
    $
    

    Il est important de remarquer que le nom d’un paramètre et la valeur de ce paramètre ne se désignent pas de la même manière.

    $ x=$x$y 	=> x : contenant, $x : contenu
    $ echo $x
    coucoubonjour
    $
    

    La nouvelle valeur de la variable x est constituée de la valeur précédente de x (chaîne coucou) à laquelle a été collée (concaténée) la valeur de la variable y (chaîne bonjour).

    Lorsque l’on souhaite effectuer ce type de concaténation, il est possible d’utiliser l’opérateur += de bash.

    $ a=coucou  b=bonjour
    $ a+=$b
    $ echo $a
    coucoubonjour
    $
    
  2. Affectation par lecture

    Elle s’effectue à l'aide de la commande interne read. Celle-ci lit une ligne entière sur l’entrée standard.

    Syntaxe : read [ var1 ... ]

    $ read a b
    bonjour Monsieur 	=> chaînes saisies par l’utilisateur et enregistrées respectivement dans les variables a et b
    $ echo $b
    Monsieur
    $
    

    Lorsque la commande interne read est utilisée sans argument, la ligne lue est enregistrée dans la variable prédéfinie du shell REPLY.

    $ read
    bonjour tout le monde
    $
    $ echo $REPLY
    bonjour tout le monde
    $
    

    L’option –p de read affiche une chaîne d’appel avant d’effectuer la lecture. La syntaxe à utiliser est : read –p chaîne_d_appel [ var ... ]

    $ read -p "Entrez votre prenom : " prenom
    Entrez votre prenom : Eric
    $
    $ echo $prenom
    Eric
    $
    

    Remarques sur la commande interne read

    • S’il y a moins de variables que de mots dans la ligne lue, le shell affecte le premier mot à la première variable, le deuxième mot à la deuxième variable, etc., la dernière variable reçoit tous les mots restants.

      $ read a b c
      un bon jour coucou
      $
      $ echo $a
      un
      $ echo $c
      jour coucou
      $
      

    • S’il y a davantage de variables que de mots dans la ligne lue, chaque variable reçoit un mot et après épuisement de ces derniers, les variables excédentaires sont vides (c.-à-d. initialisées à la valeur null).

      $ read a b
      un
      $
      $ echo $a
      un
      $
      $ echo $b
         => valeur null
      $
      

2.1.2. Variable en « lecture seule »

Pour définir une variable dont la valeur ne doit pas être modifiée (appelée constante dans d’autres langages de programmation), on utilise la syntaxe :

declare –r nom=valeur [ nom=valeur ... ]

$ declare -r mess=bonjour
$

On dit que la variable mess possède l’attribut r.

Une tentative de modification de la valeur d’une constante provoque une erreur.

$ mess=salut
bash: mess : variable en lecture seule
$

Pour connaître la liste des constantes définies : declare –r

$ declare -r
declare -r BASHOPTS= "checkwinsize:cmdhist:complete_fullquote:expand_alia ses:extglob:extquote:force_fignore:globasciiranges:histappend:interactive_comments:progcomp:promptvars:sourcepath"
declare -ar BASH_VERSINFO=([0]="5" [1]="1" [2]="4" [3]="1" [4]="release" [5]="x86_64-pc-linux-gnu")
declare -ir EUID="1000"
declare -ir PPID="2192"
declare -r SHELLOPTS="braceexpand:emacs:hashall:histexpand:history:interactive-comments:monitor"
declare -ir UID="1000"
declare -r mess="bonjour"
$

Plusieurs constantes sont prédéfinies dont le tableau BASH_VERSINFO (attribut a), les entiers EUID, PPID et UID (attribut i).

2.1.3. Variables d'environnement

Par défaut, lorsqu’un utilisateur définit une variable var, celle-ci reste locale à l’interpréteur bash qui l’a créée. Cela signifie par exemple que si l’utilisateur lance l’exécution d’un deuxième shell, celui-ci n’aura pas accès à la variable var.

				
$ a=coucou		=> définition de la variable locale a
$
$ echo $a
coucou		=> la valeur de a est accessible
$
$ bash		=> création d’un shell bash, fils de l’interpréteur précédent, qui
$			=>        interprètera les futures commandes saisies
$ ps
  PID TTY          TIME CMD
 9918 pts/1    00:00:00 bash		=> bash père
 9933 pts/1    00:00:00 bash		=> bash fils
 9948 pts/1    00:00:00 ps
$
$ echo $a
		=> la variable a est inconnue pour le shell bash fils
$
$ exit		=> terminaison du shell fils
exit
$
$ ps
  PID TTY          TIME CMD
 9918 pts/1    00:00:00 bash		=> bash père
 9949 pts/1    00:00:00 ps
$
$ echo $a
coucou
$

En fait, l’ensemble des variables accessibles à un interpréteur (ou plus généralement à un processus) peut se décomposer en deux classes :

  • les variables locales (comme la variable a de l’exemple précédent) : elles disparaissent lorsque l’interpréteur (ou le processus) se termine

  • les variables d’environnement : celles-ci ont la particularité d’être automatiquement transmises à sa descendance, c.-à-d. copiées, à tous les shells fils (ou processus fils) qu’il créera dans le futur.

Des exemples de variables d’environnement usuelles sont PATH et HOME.

Pour créer une variable d’environnement ou faire devenir variable d’environnement une variable déjà existante, on utilise la commande interne export.

	
$ a=coucou
$
$ b=bonjour		=> définition de la variable locale b
$
$ export b		=> la variable b devient une variable d’environnement
$
$ export c=bonsoir	=> définition de la variable d’environnement c
$
$ bash			=> création d’un shell fils
$
$ echo $a
			=> la variable a est inconnue
$ echo $b
bonjour
$
$ echo $c
bonsoir			=> les variables b et c sont connues du shell fils
$
$ exit			=> fin du shell fils
exit
$

La commande interne declare -p affiche la liste des variables définies accompagnées de leur valeur et attributs alors que la commande unix env affiche uniquement les variables d'environnement.

	
$ declare -p
	. . .
declare -- a="coucou"
declare -x b="bonjour"
declare -x c="bonsoir"
	. . .
$
$ env
. . .			=> la variable a est absente de l’environnement
b=bonjour
c=bonsoir
. . .
$

La transmission des variables d’environnement est unidirectionnelle : du processus père vers le(s) processus fils. Si un processus fils modifie la valeur d’une variable d’environnement, seule sa copie locale en sera affectée ; cette modification sera transparente pour son processus père.

	
$ export a=coucou
$ 
$ bash
$ echo $a
coucou
$ 
$ a=bonsoir		=> modification de la variable d’environnement a dans le shell fils
$ echo $a
bonsoir
$ 
$ exit
exit
$ 
$ echo $a		 
coucou		=> la valeur n’a pas été modifiée dans le shell père
$