Non so getopt
ma l' getopts
integrato può essere usato per gestire solo opzioni lunghe come questa:
while getopts :-: o
do case "$o$OPTARG" in
(-longopt1) process ;;
(-longopt2) process ;;
esac; done
Naturalmente, così com'è, ciò non funziona se si suppone che le opzioni lunghe abbiano argomenti. Si può fare, però, ma, come ho imparato lavorando su questo. Mentre inizialmente l'ho incluso qui mi sono reso conto che per le opzioni lunghe non ha molta utilità. In questo caso stava solo accorciando i miei case
(match)
campi di un singolo carattere prevedibile. Ora, quello che so, è che è eccellente per le opzioni brevi - è molto utile quando si esegue il ciclo su una stringa di lunghezza sconosciuta e selezionando singoli byte in base alla sua stringa di opzioni. Ma quando l'opzione è l'arg, non c'è molto che stai facendo con una for var do case $var in
combinazione che potrebbe fare. È meglio, penso, per mantenerlo semplice.
Sospetto che lo stesso sia vero, getopt
ma non ne so abbastanza per dirlo con certezza. Dato il seguente array arg, mostrerò il mio piccolo parser arg - che dipende principalmente dalla relazione di valutazione / assegnazione che ho imparato ad apprezzare per alias
e $((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
Questa è la stringa arg con cui lavorerò. Adesso:
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
Ciò elabora l'array arg in uno di due modi diversi a seconda che tu lo consegni uno o due insiemi di argomenti separati dal --
delimitatore. In entrambi i casi si applica alle sequenze di elaborazione nell'array arg.
Se lo chiami come:
: $((SHIFT$$=3)); aopts --lopt1 --lopt2 -- "$@"
Il suo primo ordine sarà quello di scrivere la sua acase()
funzione per assomigliare a:
acase() case "$a" in
(--lopt1) f=lopt1; aset "?$(($f)):";;
(--lopt2) f=lopt2; aset "?$(($f)):";;
(--*) f=ignored; aset "?$(($f)):";;
(*) aset "" "$a";;esac
E accanto a shift 3
. La sostituzione dei comandi nella acase()
definizione della funzione viene valutata quando la shell chiamante crea qui i documenti di input della funzione, ma acase()
non viene mai chiamata o definita nella shell chiamante. Si chiama nella subshell, ovviamente, e quindi in questo modo è possibile specificare dinamicamente le opzioni di interesse sulla riga di comando.
Se lo si passa a un array non delimitato, si popola semplicemente acase()
con le corrispondenze per tutti gli argomenti che iniziano con la stringa --
.
La funzione esegue praticamente tutta la sua elaborazione nella subshell, salvando iterativamente ciascuno dei valori di arg in alias assegnati con nomi associativi. Quando è finito, stampa tutti i valori con alias
cui è stato salvato , che è specificato da POSIX per stampare tutti i valori salvati citati in modo tale che i loro valori possano essere reintegrati nella shell. Quindi quando lo faccio ...
aopts --lopt1 --lopt2 -- "$@"
Il suo output è simile al seguente:
...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'
Mentre scorre l'elenco arg, verifica la corrispondenza con il case case. Se trova una corrispondenza lì lancia una bandiera - f=optname
. Fino a quando non troverà di nuovo un'opzione valida, aggiungerà ogni argomento successivo a un array che costruisce in base al flag corrente. Se la stessa opzione viene specificata più volte i risultati si combinano e non sovrascrivono. Tutto ciò che non è nel caso - o qualsiasi argomento che segue le opzioni ignorate - viene assegnato a un array ignorato .
L'output è protetto dalla shell per l'input della shell automaticamente dalla shell, e quindi:
eval "$(: $((SHIFT$$=3));aopts --lopt1 --lopt2 -- "$@")"
... dovrebbe essere perfettamente sicuro. Se per qualsiasi motivo non è sicuro, probabilmente dovresti presentare una segnalazione di bug al tuo manutentore della shell.
Assegna due tipi di valori alias per ogni corrispondenza. Innanzitutto, imposta un flag: ciò si verifica indipendentemente dal fatto che un'opzione preceda o meno argomenti non corrispondenti. Quindi si verificherà qualsiasi occorrenza di --flag
nell'elenco arg flag=1
. Questo non è composto - --flag --flag --flag
solo ottiene flag=1
. Questo valore fa però incremento - per qualsiasi argomento che potrebbe seguirlo. Può essere usato come chiave di indice. Dopo aver fatto quanto eval
sopra posso fare:
printf %s\\n "$lopt1" "$lopt2"
...ottenere...
8
1
E così:
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
PRODUZIONE
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
E agli argomenti che non corrispondevano, sostituirei ignorati nel for ... in
campo sopra per ottenere:
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
, ma si sta utilizzando il/usr/bin/getopt
comando.