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
où
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.