Une compilation de documentations   { en , fr }

Parcourir les paramètres positionnels d'un script shell... dans les deux sens

Étiquettes:
Créé en:
Dernière modification:
Auteur:
Xavier Béguin

Parcours des arguments du premier au dernier

Dans les interpréteurs de commandes du type bash, les paramètres positionnels du script ou d'une fonction peuvent être obtenus individuellement à l'aide des variables affectées automatiquement par l'interpréteur : $1 (pour le premier arguments), $2 pour le deuxième, $3, etc.

Mais pour parcourir successivement un à un les paramètres positionnels passés à un script ou une fonction shell, on peut simplement utiliser une boucle for de ce genre :

1for arg
2do
3 echo "J'ai reçu l'argument $arg";
4done

Cela fonctionne car, utilisé sans le mot-clef in, for effectue par défaut une boucle sur tous les paramètres positionnels, ce qui revient donc au même que d'utiliser for arg in "$@" (qui fonctionne aussi, et qui a d'ailleurs le mérite d'être plus explicite, "$@" étant remplacé par la liste des arguments positionnels).

Parcours des arguments du dernier au premier

Pour parcourir la liste de ces paramètres à l'envers (c'est à dire du dernier au premier paramètre positionel), on doit avoir recours à l'utilisation de la fonction interne du shell eval :

1for i in $(seq $# -1 1)
2do
3 arg="$(eval "echo \$$i")"
4 echo "J'ai reçu l'argument $arg"
5done

for effectue ici une boucle sur les numéros de paramètres qu'on veut traiter, du dernier paramètre, fourni par la variable automatique $#, au premier, numéroté 1 ($0 n'est pas un paramètre, mais le nom du script).

Ensuite, pour lire la valeur du paramètre positionnel de numéro $i (c'est à dire $4, $3, …), on utilise eval à la ligne 3 pour exécuter la commande echo \$$i.

Pour bien comprendre cette ligne 3, notez bien que :

  • la commande fournie à eval est évaluée deux fois : une fois lors de l'exécution normale du script, puis le résultat de cette première évaluation sera évalué par la fonction eval elle-même ;
  • il faut donc déspécialiser le premier $ à l'aide d'une barre oblique inverse pour que la première évaluation ne l'interprète pas et le conserve tel quel ;
  • lors de la seconde évalution, ce premier $ sera cette fois utilisé en conjonction avec le chiffre obtenu par l'évaluation du $i qui le suit : eval va donc exécuter une fonction qui ressemblera à echo $3 (le chiffre changeant bien sûr en fonction de la valeur de i) et en renverra le résulat.

Alternative spécifique à l'interpréteur bash

Avec l'interpréteur bash, parcourir la liste de ces paramètres à l'envers peut être réalisé sans avoir recours à eval, grâce au mécanisme de développement indirect spécifique à bash :

1for i in $(seq $# -1 1)
2do
3 arg=${!i}
4 echo "argument $arg";
5done

Attention : ces indirections de variables n'existent pas dans la norme POSIX (norme IEEE 1003.1) et sont donc spécifiques à l'interpréteur bash. Elles ne fonctionneront pas avec les interpréteurs se limitant à cette norme (ce qui est par exemple généralement le cas lorsque vous utilisez l'interpréteur simplement nommé sh).

Ici, pour lire la valeur du paramètre positionnel (contenue dans $4, $3, ...), on introduit un niveau d'indirection de variable grâce au point d'exclamation : il indique qu'on veut lire la valeur d'une variable dont le nom est contenu dans une autre variable.

Ainsi, si $i contient 3, ${!i} sera remplacé par la valeur de la variable $3, donc le troisième argument positionnel du script ou de la fonction, tout comme le ferait la commande eval "echo \$$i".

Corollaire : grâce à ce mécanisme de développement indirect de bash, le dernier paramètre positinel d'un script ou d'une fonction bash peut donc être obtenu directement grâce à l'expression ${!#} que vous devriez maintenant pouvoir comprendre correctement.

Notez qu'on a recours à la commande seq plutôt qu'au générateur de série interne de bash (du type {10..1}) car ce dernier utilise les accolades qui sont évaluées avant le remplacement des variables. On ne peut donc pas écrire quelque chose comme {$#..1} pour obtenir la série de chiffres entre le dernier et le premier argument positionnel.