getopt
i getopts
są różnymi zwierzętami, a ludzie wydają się mieć trochę niezrozumienia tego, co robią. getopts
to wbudowane polecenie do bash
przetwarzania 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ć. getopt
jest jednak zewnętrznym programem narzędziowym i tak naprawdę nie przetwarza twoich opcji tak, jak robią to np. bash getopts
, Getopt
moduł Perl lub moduły Python optparse
/ argparse
. Wystarczy getopt
kanonizować przekazane opcje - tzn. Przekonwertować je na bardziej standardową formę, aby skrypt powłoki mógł je łatwiej przetwarzać. Na przykład aplikacja getopt
moż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ć, getopt
jeś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.
-o
powyżej) wartość musi być oddzielnym argumentem (po spacji).
Dlaczego warto korzystać getopt
zamiastgetopts
? Podstawowym powodem jest to, że tylko GNU getopt
zapewnia obsługę opcji wiersza polecenia o długiej nazwie. 1 (GNU getopt
jest 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 getopt
jest 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 set
linii), 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ą getopt
jednak można grupować opcje jednoliterowe, stosować krótsze, niejednoznaczne formy długich opcji, używać albo --file foo.txt
lub --file=foo.txt
, używać albo -m 4096
lub -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 getopt
i GNU getopt
, z różnymi funkcjami i różnymi konwencjami wywoływania. 2 Podstawowy getopt
jest 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 getopts
robi to dobrze. Powyższy kod nie będzie działał w podstawowym języku getopt
. GNU getopt
jest 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 getopt
aby 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 -o
i długie opcje po --long
. Umieść dwukropek po opcjach, które przyjmują wartość.
Wreszcie, jeśli widzisz kod, który właśnie set
zamiast tego eval set
, został napisany dla BSD getopt
. Powinieneś to zmienić, aby użyć eval set
stylu, który działa dobrze w obu wersjach getopt
, podczas gdy zwykły set
nie działa poprawnie z GNU getopt
.
1 Faktycznie, getopts
w ksh93
podporach długo nazwie opcje, ale ta skorupa nie jest używany tak często, jak bash
. Wzsh
użyj, zparseopts
aby 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).