getopte getoptssono bestie diverse, e le persone sembrano avere un po 'di incomprensioni su ciò che fanno. getoptsè un comando integrato bashper elaborare le opzioni della riga di comando in un ciclo e assegnare ciascuna opzione trovata e valore a sua volta alle variabili integrate, in modo da poterle ulteriormente elaborare. getopt, tuttavia, è un programma di utilità esterno e in realtà non elabora le opzioni per te come fanno bash getopts, il Getoptmodulo Perl o Python optparse/ module argparse. Tutto ciò che getoptfa è canonicalizzare le opzioni che vengono passate, ovvero convertirle in un modulo più standard, in modo che sia più facile per uno script shell elaborarle. Ad esempio, un'applicazione di getoptpotrebbe convertire quanto segue:
myscript -ab infile.txt -ooutfile.txt
in questo:
myscript -a -b -o outfile.txt infile.txt
Devi eseguire tu stesso l'elaborazione effettiva. Non è necessario utilizzare getoptaffatto se si applicano varie restrizioni sul modo in cui è possibile specificare le opzioni:
- metti solo un'opzione per argomento;
- tutte le opzioni vanno prima di qualsiasi parametro posizionale (cioè argomenti non di opzione);
- per le opzioni con valori (ad es.
-osopra), il valore deve andare come argomento separato (dopo uno spazio).
Perché usare getoptinvece di getopts? Il motivo di base è che solo GNU getoptoffre supporto per le opzioni della riga di comando con nome lungo. 1 (GNU getoptè l'impostazione predefinita su Linux. Mac OS X e FreeBSD sono forniti di base e non molto utili getopt, ma la versione GNU può essere installata; vedi sotto).
Ad esempio, ecco un esempio dell'uso di GNU getopt, da un mio script chiamato 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
Ciò consente di specificare opzioni simili --verbose -dm4096 --minh=20 --maxhe 40 --debugfi="/Users/John Johnson/debug.txt"o simili. L'effetto della chiamata a getoptè di canonicalizzare le opzioni in --verbose -d -m 4096 --minheap 20 --maxheap 40 --debugfile "/Users/John Johnson/debug.txt"modo da poterle elaborare più facilmente. La citazione intorno "$1"ed "$2"è importante in quanto garantisce che gli argomenti con spazi siano gestiti correttamente.
Se elimini le prime 9 righe (tutto su attraverso la eval setriga), il codice continuerà a funzionare ! Tuttavia, il tuo codice sarà molto più selettivo in quale tipo di opzioni accetta: In particolare, dovrai specificare tutte le opzioni nel modulo "canonico" sopra descritto. Con l'uso di getopt, tuttavia, è possibile raggruppare opzioni a lettera singola, utilizzare forme più brevi non ambigue di opzioni lunghe, utilizzare lo stile --file foo.txto --file=foo.txt, utilizzare lo stile -m 4096o -m4096, mescolare opzioni e non opzioni in qualsiasi ordine, ecc. getoptgenera inoltre un messaggio di errore se vengono rilevate opzioni non riconosciute o ambigue.
NOTA : Esistono in realtà due versioni totalmente diverse di getopt, base getopte GNU getopt, con caratteristiche diverse e convenzioni di chiamata diverse. 2 Basic getoptè piuttosto rotto: non solo non gestisce le opzioni lunghe, ma non può nemmeno gestire spazi incorporati all'interno di argomenti o argomenti vuoti, mentre lo getoptsfa bene. Il codice sopra non funzionerà in base getopt. GNU getoptè installato di default su Linux, ma su Mac OS X e FreeBSD deve essere installato separatamente. Su Mac OS X, installa MacPorts ( http://www.macports.org ) e quindi esegui sudo port install getoptl'installazione di GNU getopt(di solito in /opt/local/bin) e assicurati che /opt/local/binsia nel percorso della shell prima di/usr/bin. Su FreeBSD, installa misc/getopt.
Una guida rapida alla modifica del codice di esempio per il tuo programma: Delle prime righe, tutto è "boilerplate" che dovrebbe rimanere lo stesso, tranne la linea che chiama getopt. È necessario modificare il nome del programma dopo -n, specificare le opzioni brevi dopo -oe le opzioni lunghe dopo --long. Inserisci i due punti dopo le opzioni che assumono un valore.
Infine, se vedi il codice che ha solo setinvece di eval set, è stato scritto per BSD getopt. Dovresti cambiarlo per usare lo eval setstile, che funziona bene con entrambe le versioni di getopt, mentre la pianura setnon funziona bene con GNU getopt.
1 In realtà, getoptsin ksh93supporti opzioni lunga di nome, ma questo guscio non è usato spesso come bash. In zsh, utilizzare zparseoptsper ottenere questa funzionalità.
2 Tecnicamente, "GNU getopt" è un termine improprio; questa versione è stata effettivamente scritta per Linux anziché per il progetto GNU. Tuttavia, segue tutte le convenzioni GNU e il termine "GNU getopt" è comunemente usato (ad esempio su FreeBSD).