Analyse et vérification des options: getopts

L'analyse des arguments d'une commande permet de
  ♦   détecter les options que l'utilisateur veut voir appliquer,
  ♦   récupérer les valeurs, noms de fichiers, de répertoire ...
  ♦   détecter des erreurs de l'utilisateur, que l'on doit identifier et expliquer clairement.
Si le programmeur veut simplifier cette analyse, il imposera une syntaxe rigide à l'appel de son script, ce qui ne le rend pas très attrayant.
Si, au contraire il souhaite apporter de la souplesse à l'appel du script, les diverses possibilités de présentation des options entraînent, si on utilise seulement les instructions 'if then ... elif ... fi' ou 'case ... esac', une suite d'instructions tellement complexe que ça marche une fois et on perd un temps fou à mettre au point sérieusement ces lignes de code.

Un outil existe, pour faciliter ce travail c'est la commande interne getopts pour les interprètes de commande (shell: bash, ksh ...), ou la fonction getopt pour les langages C ou C++, ou la classe GetOpt ... pour Java, Perl ... Nous présentons ci-après un exemple d'analyse, programmé pour l'interprète de commande ksh ou bash.

Après avoir exposé un exemple de traitement, nous présentons brièvement getopts, puis des appels au script, et enfin la programmation du script présenté en exemple.

Un exemple de script

De façon ultra-classique, nous voulons effectuer un traitement sur certains fichiers; le traitement importe peu, mais on peut imaginer une copie de sauvegarde. Précisons le choix des fichiers.
On propose de travailler sur les fichiers du répertoire courant, ou sur les fichiers d'un répertoire dont le nom est fourni avec l'option -d.
On ajoute une dose d'interaction possible avec l'option -i. Si elle est présente, l'utilisateur est interrogé pour chaque fichier pour qu'il puisse confirmer ou annuler le traitement sur ce fichier. A l'inverse, si elle est absente, le traitement est effectué systématiquement sur tous les fichiers.
On ajoute une dernière possibilité: l'utilisateur peut restreindre le traitement, par l'option -n, aux fichiers nouveaux, c'est à dire du jour.
Bien évidemment l'option -h est présente, pour obtenir un texte d'aide, sans traitement.
Enfin si la commande n'a aucun argument, alors elle agît sur le répertoire courant, sans interagir avec l'utilisateur (comportement par défaut si -i est absent), et sur tous les fichiers de ce répertoire (comportement par défaut si -n est absent).

Commande interne getopts

La commande getops est l'outil standard d'analyse des options d'une commande unix; rappelons que les options figurent toujours en début de commande.

Voici la syntaxe d'utilisation:
              getopts descriptionOptions option

1.   La variable descriptionOptions est fournie par l'utilisateur ( :d:in avec l'exemple ci-dessus), et sa valeur obéit à des conventions. D'une part, pour chaque option figure son caractère (avec l'exemple précédent: d, i, n), et la nécessité d'avoir une valeur pour cette option (marquée par la présence de : suivant le caractère de l'option; cf d: ci-dessus). D'autre part la détection d'option invalide est silencieuse si : est le premier caractère de descriptionOptions.
2.   La variable option est remplie par l'interpète de commande avec le caractère de l'option détectée (ou deux caractères conventionnels: '?' indique une option invalide, ':' indique une option mal utiliée ).

Remarques:
  ♦   'getops' prend en compte les options sans paramètre et les options associées à une valeur.
  ♦   'getops' extrait une seule option de la commande analysée; donc de façon standard 'getops' est appelé dans une instruction répétitive (un while ci-dessous).

Deux variables sont utilisées par cette commande et sont disponibles au programmeur:
  ♦   OPTARG est le plus utile au programmeur
  ♦   OPTIND est le numéro du prochain argument de la commande à analyser

Des appels du script

Voici quelques utilisations correctes du script présenté ci-dessus, avec la souplesse habituelle: options séparées ou pas, nom de répertoire accolé à l'option -d ou séparé par des espaces ... traiter traiter -h traiter -in traiter -i -n traiter -ind$HOME traiter -ind $HOME Voici d'autres exemples d'utilisation incorrecte, servant à tester la programmation (en particulier la vérification des droits sur le répertoire concerné). traiter -d # pas de valeur pour option -d traiter -id # pas de valeur pour option -d traiter -di # repertoire=i (dans doute invalide) traiter -d i # repertoire=i (dans doute invalide) # incorrect si droit r seul, sur le répertoire aaa mkdir aaa; chmod u-r aaa traiter -d aaa # incorrect si droit x seul, sur un répertoire aaa chmod u+r aaa; chmod u-x aaa traiter -d aaa

Le script

Après la définition de la fonction usage, on trouve trois parties: la définition des valeurs par défaut, l'analyse des options de la commande par getopts puis la partie traitement (ultra-réduite car ce n'est pas l'objet de cette page).
Remarquer le traitement à part de l'option d'aide, -h.

# exemple -h # exemple [-i] -[n] [-d nomRépertoire] # srcipt illustrant l'intérête de getopts usage() { nom=`basename $0` echo "+" echo "+ + " $nom [-i] -[n] [-d nomRépertoire] echo "+ + " $nom -h echo "+" } # ## ## ## 1: VALEURS PAR DEFAUT ## ## ## ## ## ## # interactif=0 nouveau=0 rep=$PWD # ## ## ## 2: ANALYSE DES OPTIONS ## ## ## ## ## ## # # Cas particulier de l'option -h: doit être seule if [ $# -eq 1 -a "$1" = -h ]; then usage; exit 2; fi # Analyse des autres options errOption=0 OPTIND=1 while getopts ":d:in" option do # echo "(-- option:$option $OPTIND - '$OPTARG' --)" case $option in d) rep=$OPTARG rep est non vide; doit être répertoire avec droit rx if ! [ -d $rep -a -r $rep -a -x $rep ]; then echo "! ! ! $rep n'est pas un répertoire accessible" >&2 exit 4 fi ;; :) # ici $OPTARG==d echo "! ! ! nom de répertoire absent" >&2 exit 4 ;; i) interactif=1 ;; n) nouveau=1 ;; \?) echo " option $OPTARG INVALIDE" >&2 errOption=3 esac done if [ $errOption == 3 ]; then usage >&2; exit $errOption; fi # ## ## ## 3: TRAITEMENT EFFECTIF ## ## ## ## ## ## # echo "interactif=$interactif nouveau=$nouveau rep='$rep'"

En ligne ...

Comme getopts est une commande interne de l'interprète de commandes, elle est souvent documentée avec l'interprète.