getopti getoptssą różnymi zwierzętami, a ludzie wydają się mieć trochę niezrozumienia tego, co robią. getoptsto wbudowane polecenie do bashprzetwarzania opcji wiersza polecenia w pętli i przypisywania każdej znalezionej opcji i wartości kolejno do wbudowanych zmiennych, aby można było je dalej przetwarzać. getoptjest jednak zewnętrznym programem narzędziowym i tak naprawdę nie przetwarza twoich opcji tak, jak robią to np. bash getopts, Getoptmoduł Perl lub moduły Python optparse/ argparse. Wystarczy getoptkanonizować przekazane opcje - tzn. Przekonwertować je na bardziej standardową formę, aby skrypt powłoki mógł je łatwiej przetwarzać. Na przykład aplikacja getoptmoże konwertować następujące elementy:
myscript -ab infile.txt -ooutfile.txt
zaangażowany w to:
myscript -a -b -o outfile.txt infile.txt
Rzeczywiste przetwarzanie należy wykonać samodzielnie. Nie musisz wcale używać, getoptjeśli wprowadzasz różne ograniczenia w sposobie określania opcji:
- umieść tylko jedną opcję na argument;
- wszystkie opcje poprzedzają parametry pozycyjne (tj. argumenty nieopcji);
- w przypadku opcji z wartościami (np.
-opowyżej) wartość musi być oddzielnym argumentem (po spacji).
Dlaczego warto korzystać getoptzamiastgetopts ? Podstawowym powodem jest to, że tylko GNU getoptzapewnia obsługę opcji wiersza polecenia o długiej nazwie. 1 (GNU getoptjest domyślny w Linuksie. Mac OS X i FreeBSD są dostarczane z podstawowym i niezbyt przydatnym programemgetopt , ale wersję GNU można zainstalować; patrz poniżej.)
Na przykład, oto przykład użycia GNU getopt, z mojego skryptu o nazwie 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
Pozwala to określić opcje takie jak --verbose -dm4096 --minh=20 --maxhe 40 --debugfi="/Users/John Johnson/debug.txt" lub podobne. Efektem wywołania getoptjest kanonizacja opcji, aby --verbose -d -m 4096 --minheap 20 --maxheap 40 --debugfile "/Users/John Johnson/debug.txt"można było łatwiej je przetworzyć. Cytowanie wokół "$1"i "$2"jest ważne, ponieważ zapewnia, że argumenty ze spacjami są poprawnie obsługiwane.
Jeśli usuniesz pierwsze 9 wierszy (wszystko wzdłuż eval setlinii), kod nadal będzie działał ! Jednak twój kod będzie znacznie bardziej wybitny pod względem rodzajów akceptowanych opcji: W szczególności będziesz musiał określić wszystkie opcje w opisanej powyżej „kanonicznej” formie. Za pomocą getoptjednak można grupować opcje jednoliterowe, stosować krótsze, niejednoznaczne formy długich opcji, używać albo --file foo.txtlub --file=foo.txt, używać albo -m 4096lub -m4096, mieszać opcje i nie-opcje w dowolnej kolejności itp. getopt wyświetla również komunikat o błędzie, jeśli znaleziono nierozpoznane lub niejednoznaczne opcje.
UWAGA : W rzeczywistości istnieją dwie całkowicie różne wersje getopt, Basic getopti GNU getopt, z różnymi funkcjami i różnymi konwencjami wywoływania. 2 Podstawowy getoptjest dość zepsuty: nie tylko nie obsługuje długich opcji, nie może nawet obsługiwać spacji wewnątrz argumentów lub pustych argumentów, podczas gdy getoptsrobi to dobrze. Powyższy kod nie będzie działał w podstawowym języku getopt. GNU getoptjest instalowane domyślnie w systemie Linux, ale w Mac OS X i FreeBSD należy je instalować osobno. W systemie Mac OS X zainstaluj MacPorts ( http://www.macports.org ), a następnie zrób to, sudo port install getoptaby zainstalować GNU getopt(zwykle w /opt/local/bin) i upewnij się, że/opt/local/bin znajduje się on na ścieżce powłoki przed/usr/bin. Na FreeBSD zainstaluj misc/getopt.
Krótki przewodnik po modyfikowaniu przykładowego kodu dla własnego programu: z pierwszych kilku linii wszystko jest „płytką kotłową”, która powinna pozostać niezmieniona, z wyjątkiem linii, która wywołuje getopt. Powinieneś zmienić nazwę programu po -n, określić krótkie opcje po -oi długie opcje po --long. Umieść dwukropek po opcjach, które przyjmują wartość.
Wreszcie, jeśli widzisz kod, który właśnie setzamiast tego eval set, został napisany dla BSD getopt. Powinieneś to zmienić, aby użyć eval setstylu, który działa dobrze w obu wersjach getopt, podczas gdy zwykły setnie działa poprawnie z GNU getopt.
1 Faktycznie, getoptsw ksh93podporach długo nazwie opcje, ale ta skorupa nie jest używany tak często, jak bash. Wzsh użyj, zparseoptsaby uzyskać tę funkcjonalność.
2 Technicznie „GNU getopt” jest mylącą nazwą; ta wersja została napisana dla Linuksa, a nie dla projektu GNU. Jest jednak zgodny ze wszystkimi konwencjami GNU, a termin „GNU getopt” jest powszechnie używany (np. W FreeBSD).