Des options en ligne de commande avec getopts
Notions théoriques
Options et arguments positionnels
Jusqu'ici, sauvegarde.sh reçoit ses dossiers directement en arguments positionnels ($1, $2...). Mais la plupart des commandes Unix (ls -la, tar -czf archive.tar.gz dossier) distinguent deux choses :
- les options, introduites par un tiret (
-v,-h,-d /tmp), qui modifient le comportement de la commande et peuvent apparaître dans n'importe quel ordre ; - les arguments positionnels, le « sujet » réel de la commande (le dossier à sauvegarder).
Bash fournit une commande interne dédiée à l'analyse de ce type d'options : getopts.
La boucle getopts
while getopts "hvd:" opt; do
case "$opt" in
h) usage; exit 0 ;;
v) verbeux=1 ;;
d) destination="$OPTARG" ;;
\?) usage; exit 1 ;;
esac
done
shift $((OPTIND - 1))
Remarquez que le traitement de chaque option repose directement sur le case vu en séance 1.
- La chaîne
"hvd:"liste les lettres d'options acceptées :h,vetd. - Une lettre seule (
h,v) est une option booléenne : présente ou absente. - Une lettre suivie de
:(d:) signifie que l'option attend une valeur, disponible ensuite dans la variable spéciale$OPTARG. $OPTINDest mis à jour à chaque itération : c'est l'indice du prochain argument à traiter, options comprises.
Après la boucle, shift $((OPTIND - 1)) est indispensable : il décale $1, $2... pour que "$@" ne contienne plus que les arguments positionnels (les dossiers), sans les options déjà traitées. Sans ce shift, $1 continuerait de pointer vers -v au lieu du premier dossier.
Gérer les erreurs de saisie
while getopts ":hvd:" opt; do
case "$opt" in
h) usage; exit 0 ;;
v) verbeux=1 ;;
d) destination="$OPTARG" ;;
\?) echo "Option inconnue : -$OPTARG" >&2; usage; exit 1 ;;
:) echo "L'option -$OPTARG nécessite une valeur" >&2; exit 1 ;;
esac
done
- La branche
\?)capte toute option inconnue (non listée dans la chaîne d'options). - En plaçant un
:en tout début de la chaîne d'options (":hvd:"),getoptspasse en mode silencieux et permet de détecter vous-même le cas d'une option qui attend une valeur mais n'en a pas reçu, via la branche:). Dans ce mode,$OPTARGcontient alors la lettre d'option fautive.
Valeurs par défaut
Une option n'étant par nature pas obligatoire, il est indispensable de fixer une valeur par défaut avant la boucle getopts, au cas où l'utilisateur ne la fournit pas :
verbeux=0
destination="/tmp/sauvegardes"
while getopts "hvd:" opt; do
...
done
Une utilisation typique du drapeau verbeux est de conditionner l'affichage de messages supplémentaires avec une fonction dédiée :
log_verbose() {
if [ "$verbeux" -eq 1 ]; then
echo "[verbose] $1"
fi
}
getopts ne gère pas les options « longues » façon --verbose ou --destination=/tmp : c'est une limitation connue, propre à la commande interne de Bash. Pour ce besoin, les scripts plus élaborés utilisent la commande externe getopt (du paquet util-linux) ou analysent "$@" manuellement avec une boucle while [ $# -gt 0 ]. Nous nous limitons ici aux options courtes, largement suffisantes pour un script d'administration courant.
Exemple pratique
#!/bin/bash
# Script : rapport.sh
# Rôle : générer un rapport, avec options -h, -v et -o
usage() {
echo "Usage : $0 [-h] [-v] [-o fichier] <dossier>"
}
verbeux=0
sortie="/tmp/rapport.txt"
while getopts ":hvo:" opt; do
case "$opt" in
h) usage; exit 0 ;;
v) verbeux=1 ;;
o) sortie="$OPTARG" ;;
\?) echo "Option inconnue : -$OPTARG" >&2; usage; exit 1 ;;
:) echo "L'option -$OPTARG nécessite une valeur" >&2; exit 1 ;;
esac
done
shift $((OPTIND - 1))
if [ $# -eq 0 ]; then
usage
exit 1
fi
dossier="$1"
if [ "$verbeux" -eq 1 ]; then
echo "[verbose] Dossier analysé : $dossier"
echo "[verbose] Fichier de sortie : $sortie"
fi
echo "Rapport pour $dossier" > "$sortie"
echo "Rapport généré : $sortie"
Exécution : ./rapport.sh -h, ./rapport.sh -v -o /tmp/rapport.txt /var/log.
Test de mémorisation/compréhension
TP pour réfléchir et résoudre des problèmes
Nous transformons sauvegarde.sh en un vrai outil en ligne de commande, avec des options -h, -d et -v.
Étape 1 — Ajouter l'option -h
Une option -h (ou --help) qui affiche l'usage et sort avec le code 0 devrait être systématique sur tout script destiné à être réutilisé, y compris par vous-même dans six mois.
Étape 2 — Ajouter l'option -d avec valeur par défaut
Fixez toujours la valeur par défaut d'une option avant la boucle getopts : si l'utilisateur ne fournit pas -d, le script doit rester utilisable avec un comportement raisonnable.
Étape 3 — Ajouter le mode verbeux et gérer les erreurs
Un script qui ignore silencieusement une option mal orthographiée (-x au lieu de -v) peut donner l'illusion que l'option a été prise en compte. Toujours signaler l'erreur et arrêter l'exécution.
Étape 4 — Décaler les arguments et récupérer les dossiers
Sans le shift $((OPTIND - 1)) de l'étape précédente, "$@" contiendrait encore les options déjà traitées (-v, -d, /tmp/sauvegardes) mélangées aux vrais dossiers à sauvegarder.