La gestion des options sous Bash

Les variables spéciales du bash $1, $2, sont employées pour traiter les paramètres d’un script. Lorsqu’il faut gérer des options avec ou sans paramètres, il est préférable d’utiliser la primitive interne du bash getopts.

Cette article présente son utilisation à travers l’implémentation d’un script ‘Hello World!‘. Il est la suite logique des deux précédentes rédactions :

  1. Arguments, paramètres et options (un rappel des termes techniques)
  2. La gestion des paramètres sous Bash (méthode qui utilise les variables spéciales)

Utilisation basique de getopts

Getopts permet de gérer les options et leurs paramètres. Il s’utilise dans une boucle while pour parcourir la liste des options possibles. Le traitement des options est défini dans un bloc d’instructions case.

Voici une première implémentation du script hw (‘Hello World!‘) :

#!/bin/bash

name='World'

while getopts "hn:" option; do
  case $option in
    n) name="$OPTARG" ;;
    h) echo "Usage: $0 [-h | -n name]" && exit 0 ;;
  esac
done

echo "Hello ${name}!"

  • “hn:” : liste des options possibles, ici h et n. Les deux points ‘:‘ après l’option n signifie qu’un paramètre lui est rattaché
  • while getopts “hn:” option; do … done : parse une à une les options passées au script. Si l’option fait partie de la liste des options valables “hn:”, alors elle est assignée à la variable $option
  • case $option in … esac : c’est dans ce bloc d’instructions que se fait la gestion des options et paramètres
  • n) name=”$OPTARG” ;; : $OPTARG (pour OPTion ARGument) est la variable contenant l’argument de l’option. Donc dans ce cas présent, le paramètre de l’option n est assigné à la variable name
  • h) echo … && exit 0 ;; : Affiche le message d’aide et quitte le script lorsque l’option est h

Utilisation du script :

# fonctionnement nominal
./hw
Hello World!
# obtenir de l'aide
./hw -h
Usage: ./hw [-h | -n name]
# changer le nom affiche
./hw -n Pierre
Hello Pierre!

La gestion des erreurs de saisie

Voici le comportement par défaut lors d’une mauvaise saisie :

# une option qui n'existe pas
./hw -s
./hw : option non permise -- s
Hello World!
# un paramètre manquant
./hw -n
./hw : l'option nécessite un argument -- n
Hello World!

Un message d’erreur est affiché mais l’éxecution du script n’est pas arrêtée pour autant. Il est donc nécessaire de gérer les erreurs manuellement. Pour se faire, il faut désactiver les messages d’erreurs en plaçant le caractère ‘:‘ en première position dans la liste des options à traiter (“hn:” devient donc “:hn:”). Ensuite il faut gérer les deux cas d’erreur possibles à l’intérieur du bloc case via les valeurs :

  • ‘?’ : option invalide (attention à bien préfixer le point d’interrogation ‘?‘ par un antislash ‘\‘ pour qu’il ne soit pas interprété)
  • :‘ : paramètre de l’option absent

while getopts ":hn:" option; do
  case $option in
    n)  name="$OPTARG" ;;
    h)  echo "Usage: $0 [-h | -n name]"       && exit 0 ;;
    :)  echo "-$OPTARG: required an argument" && exit 1 ;;
    \?) echo "-$OPTARG: unknown option"       && exit 1 ;;
  esac
done

Ce qui donne à l’usage :

# une option qui n'existe pas
./hw -s
-s: unknown option
# un paramètre manquant
./hw -n
-n: required an argument

Remarque : Losqu’il y a une erreur, la variable $OPTARG contient la valeur de l’option récupérée et non plus la valeur de son paramètre.

La gestion des arguments (getopts + variables spéciales)

Pour gérer les arguments il suffit de commencer par traiter les options et leurs paramètres avec getopts, puis les paramètres restant avec les variables spéciales (cf. La gestion des paramètres sous Bash). Le “pivot” entre ces deux méthodes se fait grâce à la primitive shift et la variable $OPTIND (OPTion INDex). shift permet de décaler les arguments. La variable $OPTIND est le pointeur d’arguments utilsé par getopts. Il s’incrémente à chaque argument parsé, il est donc utilisé avec shift pour décaler la liste de toute les options et leurs paramètres afin de ne se retrouver qu’avec les paramètres de la commande (ceux qui restent).

Par exemple, pour rajouter un paramètre qui permet de répéter plusieurs fois le message ‘Hello World!‘ :

#!/bin/bash

name='World'

while getopts ":hn:" option; do
  case $option in
    n)  name="$OPTARG" ;;
    h)  echo "Usage: $0 [-h | -n name]"       && exit 0 ;;
    :)  echo "-$OPTARG: required an argument" && exit 1 ;;
    \?) echo "-$OPTARG: unknown option"       && exit 1 ;;
  esac
done

shift $((OPTIND-1))

if [ $# -eq 1 ]; then
  if ! [[ $1 =~ ^[0-9]+$ ]] ; then
    echo "error: $1 Not a number" && exit 1
  else
    repeat=$1
  fi
else
  repeat=1
fi

for (( i=0; i<$repeat; i++ )); do
  echo "Hello ${name}!"
done

Utilisation :

# sans parametre
./hw
Hello World!
# parametre valide
./hw -n Pierre 2
Hello Pierre!
Hello Pierre!
# mauvaise saisie
./hw d
error: 'd' not a number

Les limites de cette solution

La solution getopts permet uniquement de gérer les options courtes (ex : -h mais pas –help) et il n’est pas possible de placer les paramètres de la commande avant les options (./hw 2 -n Pierre ne tiendra pas compte du paramètre 2). Pour franchir ces limites il faudra s’orienter vers d’autre solutions tel que des commandes externes (xargs, getopt à ne surtout pas confondre avec la builtin getopts), ou des librairies tierces (bash-argsparse).

Vous avez aimé ?

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

18 + 6 =