Não sei sobre getopt
, mas o getopts
builtin pode ser usado para lidar apenas com opções longas como esta:
while getopts :-: o
do case "$o$OPTARG" in
(-longopt1) process ;;
(-longopt2) process ;;
esac; done
Claro que, como é, isso não funciona se as opções longas tiverem argumentos. Isso pode ser feito, porém, como aprendi trabalhando nisso. Embora eu inicialmente tenha incluído aqui, percebi que, para opções longas, não tem muita utilidade. Nesse caso, estava apenas encurtando meus campos case
(match)
por um único caractere previsível. Agora, o que eu sei, é que é excelente para opções curtas - é mais útil quando está em loop em uma cadeia de comprimento desconhecido e selecionando bytes simples de acordo com sua string de opção. Mas quando a opção é o arg, não há muita coisa que você esteja fazendo com uma combinação for var do case $var in
que poderia fazer. É melhor, penso eu, manter isso simples.
Eu suspeito que o mesmo acontece com getopt
, mas eu não sei o suficiente para dizer com certeza. Dada a seguinte matriz arg, demonstrarei meu próprio analisador de argos - que depende principalmente da relação de avaliação / atribuição que passei a apreciar para 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
Essa é a string arg que eu vou trabalhar. Agora:
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
Isso processa a matriz arg de duas maneiras diferentes, dependendo se você a entrega a um ou dois conjuntos de argumentos separados pelo delimitador --
. Em ambos os casos, aplica-se a seqüências de processamento para o array arg.
Se você ligar assim:
: $((SHIFT$$=3)); aopts --lopt1 --lopt2 -- "$@"
Sua primeira ordem de negócio será escrever sua função acase()
para se parecer com:
acase() case "$a" in
(--lopt1) f=lopt1; aset "?$(($f)):";;
(--lopt2) f=lopt2; aset "?$(($f)):";;
(--*) f=ignored; aset "?$(($f)):";;
(*) aset "" "$a";;esac
E ao lado de shift 3
. A substituição de comando na definição da função acase()
é avaliada quando o shell de chamada constrói a entrada da função here-documents, mas acase()
nunca é chamado ou definido no shell de chamada. É chamado no subshell, é claro, e assim você pode especificar dinamicamente as opções de interesse na linha de comando.
Se você entregar uma matriz não delimitada, ele simplesmente preencherá acase()
com correspondências para todos os argumentos iniciados com a string --
.
A função faz praticamente todo o seu processamento no subshell - salvando iterativamente cada um dos valores do arg para aliases designados com nomes associativos. Quando é através dele imprime todos os valores salvos com alias
- que é POSIX-especificado para imprimir todos os valores salvos citados de tal forma que seus valores podem ser reinputados para o shell. Então quando eu faço ...
aopts --lopt1 --lopt2 -- "$@"
Sua saída é assim:
...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'
Conforme percorre a lista de argumentos, verifica o bloco de casos para uma correspondência. Se encontrar uma correspondência lá, ele lança um sinalizador - f=optname
. Até encontrar novamente uma opção válida, ele adicionará cada argumento subseqüente a uma matriz que ele cria com base no sinalizador atual. Se a mesma opção for especificada várias vezes, os resultados serão compostos e não serão substituídos. Qualquer coisa que não esteja no caso - ou qualquer argumento após as opções ignoradas - é atribuído a uma matriz ignorada .
A saída é protegida por shell para entrada de shell automaticamente pelo shell e, portanto:
eval "$(: $((SHIFT$$=3));aopts --lopt1 --lopt2 -- "$@")"
... deve ser perfeitamente seguro. Se por algum motivo não for seguro, então você provavelmente deve enviar um relatório de bug ao seu mantenedor do shell.
Ele atribui dois tipos de valores de alias para cada correspondência. Primeiro, ele define um sinalizador - isso ocorre se uma opção precede ou não argumentos correspondentes. Portanto, qualquer ocorrência de --flag
na lista de argumentos acionará flag=1
. Isso não é composto - --flag --flag --flag
apenas obtém flag=1
. Este valor faz incrementar - para quaisquer argumentos que possam segui-lo. Pode ser usado como uma chave de índice. Depois de fazer o eval
acima, posso fazer:
printf %s\n "$lopt1" "$lopt2"
... para obter ...
8
1
E assim:
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
OUTPUT
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 para args que não correspondiam, eu substituiria ignorado no campo for ... in
acima para obter:
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