getopt
und getopts
sind verschiedene Tiere, und die Leute scheinen ein bisschen Missverständnis darüber zu haben, was sie tun. getopts
ist ein integrierter Befehl zum bash
Verarbeiten von Befehlszeilenoptionen in einer Schleife und zum Zuweisen jeder gefundenen Option und jedes gefundenen Werts zu integrierten Variablen, damit Sie sie weiter verarbeiten können. getopt
Es handelt sich jedoch um ein externes Dienstprogramm, das Ihre Optionen für Sie nicht so verarbeitet, wie es beispielsweise Bash getopts
, das Perl- Getopt
Modul oder Python optparse
/ argparse
Module tun. Alles, getopt
was Sie tun müssen, ist, die übergebenen Optionen zu kanonisieren - dh sie in ein Standardformular zu konvertieren, damit ein Shell-Skript sie leichter verarbeiten kann. Beispielsweise kann eine Anwendung von getopt
Folgendes konvertieren:
myscript -ab infile.txt -ooutfile.txt
das sehr gut finden:
myscript -a -b -o outfile.txt infile.txt
Sie müssen die eigentliche Bearbeitung selbst vornehmen. Sie müssen überhaupt nicht verwenden, getopt
wenn Sie verschiedene Einschränkungen für die Angabe von Optionen vornehmen:
- Geben Sie nur eine Option pro Argument an.
- Alle Optionen stehen vor Positionsparametern (dh Argumenten ohne Option).
- Bei Optionen mit Werten (z. B.
-o
oben) muss der Wert als separates Argument (nach einem Leerzeichen) angegeben werden.
Warum getopt
statt verwenden getopts
? Der Hauptgrund ist, dass nur GNU getopt
Ihnen Unterstützung für lange benannte Befehlszeilenoptionen bietet. 1 (GNU getopt
ist die Standardeinstellung unter Linux. Mac OS X und FreeBSD werden mit einer einfachen und nicht sehr nützlichen Version geliefertgetopt
Version , aber die GNU-Version kann installiert werden. Siehe unten.)
Hier ist zum Beispiel ein Beispiel für die Verwendung von GNU getopt
aus einem meiner Skripte mit dem Namen 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
Auf diese Weise können Sie Optionen wie --verbose -dm4096 --minh=20 --maxhe 40 --debugfi="/Users/John Johnson/debug.txt"
oder ähnlich angeben . Der Aufruf von getopt
besteht darin, die Optionen zu kanonisieren, --verbose -d -m 4096 --minheap 20 --maxheap 40 --debugfile "/Users/John Johnson/debug.txt"
damit Sie sie einfacher verarbeiten können. Das Zitieren um "$1"
und "$2"
ist wichtig, da es sicherstellt, dass Argumente mit Leerzeichen richtig behandelt werden.
Wenn Sie die ersten 9 Zeilen löschen (alles durch die eval set
Zeile), funktioniert der Code weiterhin ! Ihr Code ist jedoch viel wählerischer in Bezug auf die Arten von Optionen, die er akzeptiert: Insbesondere müssen Sie alle Optionen in der oben beschriebenen "kanonischen" Form angeben. Mit der Verwendung von getopt
können Sie jedoch Einzelbuchstabenoptionen gruppieren, kürzere, nicht mehrdeutige Formen von Langoptionen verwenden, entweder den --file foo.txt
oder --file=foo.txt
-Stil verwenden, entweder den -m 4096
oder -m4096
-Stil verwenden, Optionen und Nichtoptionen in beliebiger Reihenfolge mischen usw. getopt
gibt auch eine Fehlermeldung aus, wenn nicht erkannte oder mehrdeutige Optionen gefunden werden.
HINWEIS : Es gibt tatsächlich zwei völlig unterschiedliche Versionen von getopt
Basic getopt
und GNU getopt
mit unterschiedlichen Funktionen und unterschiedlichen Anrufkonventionen. 2 Basic getopt
ist ziemlich kaputt: Es verarbeitet nicht nur keine langen Optionen, sondern auch nicht einmal eingebettete Leerzeichen innerhalb von Argumenten oder leeren Argumenten, wohingegen getopts
dies richtig ist. Der obige Code funktioniert nicht in Basic getopt
. GNU getopt
wird standardmäßig unter Linux installiert, muss jedoch unter Mac OS X und FreeBSD separat installiert werden. Installieren Sie unter Mac OS X MacPorts ( http://www.macports.org ) und sudo port install getopt
installieren Sie dann GNU getopt
(normalerweise in /opt/local/bin
) und stellen Sie sicher, dass /opt/local/bin
sich das in Ihrem Shell-Pfad befindet/usr/bin
. Installieren Sie unter FreeBSD misc/getopt
.
Eine Kurzanleitung zum Ändern des Beispielcodes für Ihr eigenes Programm: Von den ersten Zeilen ist alles "Boilerplate", das bis auf die aufrufende Zeile gleich bleiben sollte getopt
. Sie sollten den Programmnamen nach ändern -n
, kurze Optionen nach -o
und lange Optionen nach angeben --long
. Setzen Sie nach Optionen, die einen Wert annehmen, einen Doppelpunkt.
Wenn Sie schließlich Code sehen, der nur set
anstelle von hat eval set
, wurde er für BSD geschrieben getopt
. Sie sollten es ändern, um den eval set
Stil zu verwenden, der mit beiden Versionen von gut funktioniert getopt
, während die Ebene set
mit GNU nicht richtig funktioniert getopt
.
1 Eigentlich getopts
in ksh93
Trägern lange genannte Optionen, aber diese Schale nicht so oft verwendet bash
. In zsh
Verwenden Sie zparseopts
diese Funktionalität zu erhalten.
2 Technisch gesehen ist "GNU getopt
" eine Fehlbezeichnung. Diese Version wurde eher für Linux als für das GNU-Projekt geschrieben. Es folgt jedoch allen GNU-Konventionen, und der Begriff "GNU getopt
" wird häufig verwendet (z. B. bei FreeBSD).