Nie wiem, getopt
ale getopts
wbudowanego można używać do obsługi tylko długich opcji takich jak ten:
while getopts :-: o
do case "$o$OPTARG" in
(-longopt1) process ;;
(-longopt2) process ;;
esac; done
Oczywiście, jak to jest, to nie działa, jeśli długie opcje mają argumenty. Można to jednak zrobić, ale jak nauczyłem się nad tym pracować. Chociaż początkowo umieściłem go tutaj, zdałem sobie sprawę, że w przypadku długich opcji nie ma wiele użyteczności. W tym przypadku skracałem moje case
(match)
pola tylko o jedną, przewidywalną postać. Teraz wiem, że doskonale nadaje się do krótkich opcji - jest najbardziej przydatny, gdy zapętla ciąg o nieznanej długości i wybiera pojedyncze bajty zgodnie z ciągiem opcji. Ale gdy opcją jest argument, niewiele można zrobić z for var do case $var in
kombinacją, którą mógłby zrobić. Myślę, że lepiej jest, aby było to proste.
Podejrzewam, że to samo dotyczy prawdy, getopt
ale nie wiem o niej wystarczająco dużo, aby powiedzieć z całą pewnością. Biorąc pod uwagę poniższą tablicę arg, zademonstruję mój własny parser arg - który zależy przede wszystkim od relacji ewaluacja / przypisanie, którą doceniam alias
i $((shell=math))
.
set -- this is ignored by default --lopt1 -s 'some '\''
args' here --ignored and these are ignored \
--alsoignored andthis --lopt2 'and
some "`more' --lopt1 and just a few more
To ciąg arg, z którym będę pracował. Teraz:
aopts() { env - sh -s -- "$@"
} <<OPTCASE 3<<\OPTSCRIPT
acase() case "\$a" in $(fmt='
(%s) f=%s; aset "?$(($f)):";;\n'
for a do case "$a" in (--) break;;
(--*[!_[:alnum:]]*) continue;;
(--*) printf "$fmt" "$a" "${a#--}";;
esac;done;printf "$fmt" '--*' ignored)
(*) aset "" "\$a";;esac
shift "$((SHIFT$$))"; f=ignored; exec <&3
OPTCASE
aset() { alias "$f=$(($f${1:-=$(($f))+}1))"
[ -n "${2+?}" ] && alias "${f}_$(($f))=$2"; }
for a do acase; done; alias
#END
OPTSCRIPT
Przetwarza tablicę arg na jeden z dwóch różnych sposobów, w zależności od tego, czy podajesz jej jeden czy dwa zestawy argumentów oddzielone --
separatorem. W obu przypadkach dotyczy to sekwencji przetwarzania do tablicy arg.
Jeśli nazwiesz to tak:
: $((SHIFT$$=3)); aopts --lopt1 --lopt2 -- "$@"
Jego pierwszym zadaniem będzie napisanie acase()
funkcji, która będzie wyglądać następująco:
acase() case "$a" in
(--lopt1) f=lopt1; aset "?$(($f)):";;
(--lopt2) f=lopt2; aset "?$(($f)):";;
(--*) f=ignored; aset "?$(($f)):";;
(*) aset "" "$a";;esac
I obok shift 3
. Podstawienie polecenia w acase()
definicji funkcji jest oceniane, gdy powłoka wywołująca buduje dane wejściowe funkcji tutaj, ale acase()
nigdy nie jest wywoływana ani definiowana w powłoce wywołującej. Jest on oczywiście wywoływany w podpowłoce, dzięki czemu można dynamicznie określać interesujące opcje w wierszu poleceń.
Jeśli podasz mu tablicę bez rozdzielaczy, po prostu zapełni acase()
się ona dopasowaniami dla wszystkich argumentów rozpoczynających się od łańcucha --
.
Funkcja praktycznie całe przetwarzanie odbywa się w podpowłoce - iteracyjnie zapisuje każdą wartość arg do aliasów przypisanych nazwami asocjacyjnymi. Po przejściu wypisuje każdą zapisaną wartość alias
- która jest określona przez POSIX, aby wydrukować wszystkie zapisane wartości cytowane w taki sposób, aby ich wartości mogły zostać ponownie wprowadzone do powłoki. Więc kiedy to zrobię ...
aopts --lopt1 --lopt2 -- "$@"
Jego dane wyjściowe wyglądają następująco:
...ignored...
lopt1='8'
lopt1_1='-s'
lopt1_2='some '\'' args'
lopt1_3='here'
lopt1_4='and'
lopt1_5='just'
lopt1_6='a'
lopt1_7='few'
lopt1_8='more'
lopt2='1'
lopt2_1='and
some "`more'
Przechodząc przez listę argumentów, sprawdza zgodność bloku bloku z przypadkiem. Jeśli znajdzie tam dopasowanie, rzuca flagę f=optname
. Dopóki nie znajdzie ponownie prawidłowej opcji, doda każdy kolejny argument do tablicy, którą buduje na podstawie bieżącej flagi. Jeśli ta sama opcja zostanie podana wiele razy, wyniki się złożą i nie będą zastępować. Wszystko, co nie jest w przypadku - lub jakiekolwiek argumenty następujące po ignorowanych opcjach - są przypisywane do ignorowanej tablicy.
Dane wyjściowe są chronione przez powłokę do automatycznego wprowadzania przez powłokę przez powłokę, a zatem:
eval "$(: $((SHIFT$$=3));aopts --lopt1 --lopt2 -- "$@")"
... powinno być całkowicie bezpieczne. Jeśli z jakiegoś powodu nie jest to bezpieczne, prawdopodobnie powinieneś zgłosić raport o błędzie do opiekuna powłoki.
Przypisuje dwa rodzaje wartości aliasów dla każdego dopasowania. Po pierwsze, ustawia flagę - dzieje się tak niezależnie od tego, czy opcja poprzedza niepasujące argumenty. Tak więc każde wystąpienie --flag
na liście argumentów zostanie uruchomione flag=1
. To się nie komplikuje - --flag --flag --flag
po prostu dostaje flag=1
. Wartość ta jednak zwiększa się - dla wszelkich argumentów, które mogą za nią następować. Może być używany jako klucz indeksu. Po wykonaniu eval
powyższych czynności mogę:
printf %s\\n "$lopt1" "$lopt2"
... żeby dostać ...
8
1
A więc:
for o in lopt1 lopt2
do list= i=0; echo "$o = $(($o))"
while [ "$((i=$i+1))" -le "$(($o))" ]
do list="$list $o $i \"\${${o}_$i}\" "
done; eval "printf '%s[%02d] = %s\n' $list"; done
WYNIK
lopt1 = 8
lopt1[01] = -s
lopt1[02] = some ' args
lopt1[03] = here
lopt1[04] = and
lopt1[05] = just
lopt1[06] = a
lopt1[07] = few
lopt1[08] = more
lopt2 = 1
lopt2[01] = and
some "`more
I do argumentów, które nie pasują, zastąpiłbym ignorowane w powyższym for ... in
polu, aby uzyskać:
ignored = 10
ignored[01] = this
ignored[02] = is
ignored[03] = ignored
ignored[04] = by
ignored[05] = default
ignored[06] = and
ignored[07] = these
ignored[08] = are
ignored[09] = ignored
ignored[10] = andthis
getopts
, ale używasz/usr/bin/getopt
polecenia.