getopt
et getopts
sont des bêtes différentes, et les gens semblent avoir un peu de malentendu sur ce qu'ils font. getopts
est une commande intégrée permettant bash
de traiter les options de ligne de commande dans une boucle et d'affecter tour à tour chaque option et valeur trouvées aux variables intégrées, afin que vous puissiez les traiter davantage. getopt
, cependant, est un programme utilitaire externe, et il ne traite pas réellement vos options pour vous comme le font par exemple bash getopts
, le Getopt
module Perl ou Python optparse
/ argparse
modules. Tout ce getopt
qui est fait est de canoniser les options qui sont passées - c'est-à-dire les convertir en une forme plus standard, afin qu'il soit plus facile pour un script shell de les traiter. Par exemple, une application de getopt
pourrait convertir les éléments suivants:
myscript -ab infile.txt -ooutfile.txt
en cela:
myscript -a -b -o outfile.txt infile.txt
Vous devez effectuer vous-même le traitement. Vous ne devez pas utiliser getopt
du tout si vous faites diverses restrictions sur la façon dont vous pouvez spécifier les options:
- ne mettez qu'une seule option par argument;
- toutes les options passent avant tous les paramètres positionnels (c'est-à-dire les arguments sans option);
- pour les options avec des valeurs (par exemple
-o
ci-dessus), la valeur doit aller comme un argument séparé (après un espace).
Pourquoi utiliser getopt
au lieu de getopts
? La raison fondamentale est que seul GNU getopt
vous permet de prendre en charge les options de ligne de commande portant un nom long. 1 (GNU getopt
est la valeur par défaut sous Linux. Mac OS X et FreeBSD sont livrés avec une version basique et pas très utilegetopt
, mais la version GNU peut être installée; voir ci-dessous.)
Par exemple, voici un exemple d'utilisation de GNU getopt
, à partir d'un de mes scripts appelé javawrap
:
# NOTE: This requires GNU getopt. On Mac OS X and FreeBSD, you have to install this
# separately; see below.
TEMP=`getopt -o vdm: --long verbose,debug,memory:,debugfile:,minheap:,maxheap: \
-n 'javawrap' -- "$@"`
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
# Note the quotes around `$TEMP': they are essential!
eval set -- "$TEMP"
VERBOSE=false
DEBUG=false
MEMORY=
DEBUGFILE=
JAVA_MISC_OPT=
while true; do
case "$1" in
-v | --verbose ) VERBOSE=true; shift ;;
-d | --debug ) DEBUG=true; shift ;;
-m | --memory ) MEMORY="$2"; shift 2 ;;
--debugfile ) DEBUGFILE="$2"; shift 2 ;;
--minheap )
JAVA_MISC_OPT="$JAVA_MISC_OPT -XX:MinHeapFreeRatio=$2"; shift 2 ;;
--maxheap )
JAVA_MISC_OPT="$JAVA_MISC_OPT -XX:MaxHeapFreeRatio=$2"; shift 2 ;;
-- ) shift; break ;;
* ) break ;;
esac
done
Cela vous permet de spécifier des options similaires --verbose -dm4096 --minh=20 --maxhe 40 --debugfi="/Users/John Johnson/debug.txt"
ou similaires. L'appel à a getopt
pour effet de canoniser les options pour --verbose -d -m 4096 --minheap 20 --maxheap 40 --debugfile "/Users/John Johnson/debug.txt"
que vous puissiez les traiter plus facilement. La citation autour "$1"
et "$2"
est importante car elle garantit que les arguments avec des espaces sont traités correctement.
Si vous supprimez les 9 premières lignes (tout en haut de la eval set
ligne), le code fonctionnera toujours ! Cependant, votre code sera beaucoup plus pointilleux dans les types d'options qu'il accepte: En particulier, vous devrez spécifier toutes les options sous la forme "canonique" décrite ci-dessus. getopt
Cependant, avec l'utilisation de , vous pouvez regrouper des options à une seule lettre, utiliser des formes non ambiguës plus courtes d'options longues, utiliser le style --file foo.txt
ou --file=foo.txt
, utiliser le style -m 4096
ou -m4096
, mélanger les options et les non-options dans n'importe quel ordre, etc. getopt
génère également un message d'erreur si des options non reconnues ou ambiguës sont trouvées.
REMARQUE : Il existe en fait deux versions totalement différentes de getopt
, de base getopt
et GNU getopt
, avec des fonctionnalités différentes et des conventions d'appel différentes. 2 Basic getopt
est assez cassé: non seulement il ne gère pas les options longues, mais il ne peut même pas gérer les espaces incorporés à l'intérieur des arguments ou des arguments vides, alors getopts
qu'il le fait correctement. Le code ci-dessus ne fonctionnera pas en base getopt
. GNU getopt
est installé par défaut sous Linux, mais sous Mac OS X et FreeBSD, il doit être installé séparément. Sur Mac OS X, installez MacPorts ( http://www.macports.org ), puis sudo port install getopt
installez GNU getopt
(généralement dans /opt/local/bin
) et assurez-vous qu'il se /opt/local/bin
trouve dans votre chemin de shell avant/usr/bin
. Sur FreeBSD, installez misc/getopt
.
Un guide rapide pour modifier l'exemple de code pour votre propre programme: Sur les premières lignes, tout est "passe-partout" qui doit rester le même, sauf la ligne qui appelle getopt
. Vous devez modifier le nom du programme après -n
, spécifier les options courtes après -o
et les options longues après --long
. Mettez deux points après les options qui prennent une valeur.
Enfin, si vous voyez du code qui vient de set
remplacer eval set
, il a été écrit pour BSD getopt
. Vous devriez le changer pour utiliser le eval set
style, qui fonctionne bien avec les deux versions de getopt
, tandis que le clair set
ne fonctionne pas correctement avec GNU getopt
.
1 En fait, getopts
in ksh93
prend en charge les options nommées depuis longtemps, mais ce shell n'est pas utilisé aussi souvent que bash
. Dans zsh
, utilisez zparseopts
pour obtenir cette fonctionnalité.
2 Techniquement, «GNU getopt
» est un terme impropre; cette version a été écrite pour Linux plutôt que pour le projet GNU. Cependant, il suit toutes les conventions GNU, et le terme "GNU getopt
" est couramment utilisé (par exemple sur FreeBSD).