Digamos, eu tenho um script que é chamado com esta linha:
./myscript -vfd ./foo/bar/someFile -o /fizz/someOtherFile
ou este:
./myscript -v -f -d -o /fizz/someOtherFile ./foo/bar/someFile
Qual é a maneira aceita de analisar esta de tal forma que em cada caso (ou alguma combinação dos dois) $v
, $f
e $d
tudo será definido para true
e $outFile
será igual a /fizz/someOtherFile
?
zparseopts -D -E -M -- d=debug -debug=d
E ter ambos-d
e--debug
na$debug
matrizecho $+debug[1]
retornará 0 ou 1 se um deles for usado. Ref: zsh.org/mla/users/2011/msg00350.htmlRespostas:
Método # 1: Usando o bash sem getopt [s]
Duas maneiras comuns de passar argumentos de pares de valores-chave são:
Bash Separado por Espaço (por exemplo,
--option argument
) (sem getopt [s])Uso
demo-space-separated.sh -e conf -s /etc -l /usr/lib /etc/hosts
saída de copiar e colar o bloco acima:
Bash é igual a separado (por exemplo,
--option=argument
) (sem getopt [s])Uso
demo-equals-separated.sh -e=conf -s=/etc -l=/usr/lib /etc/hosts
saída de copiar e colar o bloco acima:
Para entender melhor a
${i#*=}
pesquisa por "Remoção de Substring" neste guia . É funcionalmente equivalente ao`sed 's/[^=]*=//' <<< "$i"`
que chama um subprocesso desnecessário ou ao`echo "$i" | sed 's/[^=]*=//'`
qual chama dois subprocessos desnecessários.Método 2: Usando o bash com getopt [s]
from: http://mywiki.wooledge.org/BashFAQ/035#getopts
Limitações do getopt (1) (
getopt
versões mais antigas e relativamente recentes ):getopt
Versões mais recentes não têm essas limitações.Além disso, o shell POSIX (e outros) oferece
getopts
que não possui essas limitações. Eu incluí um simplistagetopts
exemplo .Uso
demo-getopts.sh -vf /etc/hosts foo bar
saída de copiar e colar o bloco acima:
As vantagens de
getopts
são:dash
.-vf filename
na maneira típica do Unix, automaticamente.A desvantagem
getopts
é que ele só pode lidar com opções curtas (-h
, não--help
) sem código adicional.Há um tutorial getopts que explica o que todas as sintaxes e variáveis significam. No bash, há também
help getopts
, o que pode ser informativo.fonte
getopt
que inclui todas as funcionalidadesgetopts
e mais algumas.man getopt
no Ubuntu 13.04 geragetopt - parse command options (enhanced)
o nome, então presumo que esta versão aprimorada seja padrão agora.getopt
não é um utilitário GNU, é parte deleutil-linux
.-gt 0
, remova seushift
após oesac
, aumente todos osshift
por 1 e inclua este caso:*) break;;
você pode manipular argumentos não opcionais. Ex: pastebin.com/6DJ57HTc–default
. No primeiro exemplo, eu aviso que, se–default
é o último argumento, não é processado (consideradas não-opt), a menos quewhile [[ $# -gt 1 ]]
é definido comowhile [[ $# -gt 0 ]]
Nenhuma resposta menciona getopt aprimorado . E a resposta mais votada é enganosa: ela ignora
-vfd
opções curtas de estilo (solicitadas pelo OP) ou opções após argumentos posicionais (também solicitadas pelo OP); e ignora erros de análise. Em vez de:getopt
no util-linux ou anteriormente GNU glibc . 1getopt_long()
a função C do GNU glibc.getopt
não pode fazer isso)script.sh -o outFile file1 file2 -v
(getopts
não faz isso)=
opções longas ao estilo:script.sh --outfile=fileOut --infile fileIn
(permitir que ambos sejam longos se forem analisados automaticamente)-vfd
(trabalho real se auto-análise)-oOutfile
ou-vfdoOutfile
getopt --test
→ valor de retorno 4.getopt
ou embutidos no shellgetopts
são de uso limitado.As seguintes chamadas
todos retornam
com o seguinte
myscript
1 getopt aprimorado está disponível na maioria dos "sistemas bash", incluindo Cygwin; no OS X, tente brew install gnu-getopt ou
sudo port install getopt
2, as
exec()
convençõesPOSIXnão têm uma maneira confiável de passar NULL binário nos argumentos da linha de comando; esses bytes prematuramente encerram aprimeira versãodo argumento3 lançada em 1997 ou antes (eu só a rastreei até 1997)
fonte
getopt
é o caminho a seguir.getopt
é que ele não pode ser usado convenientemente em scripts de wrapper, onde é possível ter poucas opções específicas para o script de wrapper e, em seguida, passar as opções de script que não são de wrapper para o executável empacotado, intacto. Digamos que eu tenho umgrep
invólucro chamadomygrep
e tenho uma opção--foo
específica paramygrep
, então não posso fazermygrep --foo -A 2
, e-A 2
passei automaticamente paragrep
; Eu preciso fazermygrep --foo -- -A 2
. Aqui está minha implementação sobre sua solução.man bash
Maneira mais sucinta
script.sh
Uso:
fonte
while [[ "$#" > 1 ]]
se eu quiser apoiar o final da linha com um sinalizador booleano./script.sh --debug dev --uglify fast --verbose
. Exemplo: gist.github.com/hfossli/4368aa5a577742c3c9f9266ed214aa58./script.sh -d dev -d prod
, resultaria emdeploy == 'prod'
. Eu usei assim mesmo: P :): +1:./script.sh -d
, não geraria um erro, mas apenas definido$deploy
como uma string vazia.de: digitalpeer.com com pequenas modificações
Uso
myscript.sh -p=my_prefix -s=dirname -l=libname
Para entender melhor a
${i#*=}
pesquisa por "Remoção de Substring" neste guia . É funcionalmente equivalente a`sed 's/[^=]*=//' <<< "$i"`
que chama um subprocesso desnecessário ou ao`echo "$i" | sed 's/[^=]*=//'`
qual chama dois subprocessos desnecessários.fonte
mount -t tempfs ...
. Pode-se provavelmente corrigir isso através de algo comowhile [ $# -ge 1 ]; do param=$1; shift; case $param in; -p) prefix=$1; shift;;
etc-vfd
opções curtas combinadas de estilo.getopt()
/getopts()
é uma boa opção. Roubado daqui :fonte
$*
está quebrado degetopt
. (Ele organiza argumentos com espaços.) Veja minha resposta para um uso adequado.Correndo o risco de adicionar outro exemplo para ignorar, aqui está o meu esquema.
-n arg
e--name=arg
Espero que seja útil para alguém.
fonte
*) die "unrecognized argument: $1"
ou coletar os argumentos em uma variável*) args+="$1"; shift 1;;
.shift 2
, emitindoshift
duas vezes em vez deshift 2
. Sugeriu a edição.Estou com cerca de 4 anos de atraso para esta pergunta, mas quero retribuir. Usei as respostas anteriores como ponto de partida para arrumar minha antiga análise ad-hoc de parâmetros. Em seguida, refatorei o código de modelo a seguir. Ele lida com parâmetros longos e curtos, usando = ou argumentos separados por espaço, bem como vários parâmetros curtos agrupados. Finalmente, ele reinsere todos os argumentos não param para as variáveis $ 1, $ 2 .. Espero que seja útil.
fonte
-c1
. E o uso de=
separar opções curtas de seus argumentos é incomum ...Eu achei o assunto de escrever uma análise portátil em scripts tão frustrante que escrevi Argbash - um gerador de código FOSS que pode gerar o código de análise de argumentos para o seu script, além de alguns recursos interessantes:
https://argbash.io
fonte
Minha resposta é amplamente baseada na resposta de Bruno Bronosky , mas eu meio que misturei suas duas implementações puras do bash em uma que eu uso com bastante frequência.
Isso permite que você tenha opções / valores separados por espaço, bem como valores definidos iguais.
Então você pode executar seu script usando:
assim como:
e ambos devem ter o mesmo resultado final.
PROS:
Permite tanto -arg = value quanto -arg value
Funciona com qualquer nome de argumento que você possa usar no bash
Festa pura. Não há necessidade de aprender / usar getopt ou getopts
CONTRAS:
Não é possível combinar args
Estes são os únicos prós / contras que consigo pensar em cima da minha cabeça
fonte
Eu acho que este é simples o suficiente para usar:
Exemplo de chamada:
fonte
-a=1
como estilo argc. Prefiro colocar primeiro as principais opções - e depois as especiais com espaçamento simples-o option
. Estou procurando a maneira mais simples vs melhor de ler argvs../myscript -v -d fail -o /fizz/someOtherFile -f ./foo/bar/someFile
com seu próprio script. opção -d não está definido como d:Expandindo a excelente resposta de @ guneysus, aqui está um ajuste que permite ao usuário usar a sintaxe que preferir, por exemplo
vs
Ou seja, os iguais podem ser substituídos por espaços em branco.
Essa "interpretação difusa" pode não ser do seu agrado, mas se você estiver criando scripts intercambiáveis com outros utilitários (como é o caso do meu, que deve funcionar com o ffmpeg), a flexibilidade é útil.
fonte
Este exemplo mostra como usar
getopt
eeval
eHEREDOC
eshift
para lidar com parâmetros de curto e longo com e sem um valor necessário que se segue. Além disso, a declaração switch / case é concisa e fácil de seguir.As linhas mais significativas do script acima são as seguintes:
Curto, direto ao ponto, legível e lida com quase tudo (IMHO).
Espero que ajude alguém.
fonte
Dou-lhe a função
parse_params
que irá analisar parâmetros a partir da linha de comando.--all
igual a-all
igualall=all
)O script abaixo é uma demonstração de trabalho de copiar e colar. Consulte a
show_use
função para entender como usarparse_params
.Limitações:
-d 1
)--any-param
e-anyparam
são equivalenteseval $(parse_params "$@")
deve ser usado dentro da função bash (não funcionará no escopo global)fonte
show_use "$@"
O EasyOptions não requer nenhuma análise:
fonte
O getopts funciona muito bem se o número 1 estiver instalado e o número 2 você pretende executá-lo na mesma plataforma. OSX e Linux (por exemplo) se comportam de maneira diferente a esse respeito.
Aqui está uma solução (não getopts) que suporta sinalizadores iguais, não iguais e booleanos. Por exemplo, você pode executar seu script desta maneira:
fonte
É assim que eu faço em uma função para evitar que os getopts sejam executados ao mesmo tempo em algum lugar mais alto da pilha:
fonte
Expandindo a resposta de @ bruno-bronosky, adicionei um "pré-processador" para lidar com algumas formatações comuns:
--longopt=val
para--longopt val
-xyz
para-x -y -z
--
para indicar o fim das bandeirasfonte
Existem várias maneiras de analisar args do cmdline (por exemplo, GNU getopt (não portátil) vs BSD (OSX) getopt vs getopts) - todos problemáticos. Esta solução é
=
separador-vxf
Exemplos: Qualquer um
fonte
Gostaria de oferecer minha versão da análise de opções, que permite o seguinte:
Também permite isso (pode ser indesejado):
Você precisa decidir antes de usar se = deve ser usado em uma opção ou não. Isso é para manter o código limpo (ish).
fonte
Solução que preserva argumentos não tratados. Demonstrações incluídas.
Aqui está a minha solução. É MUITO flexível e diferente de outros, não deve exigir pacotes externos e manipula os argumentos restantes de maneira limpa.
O uso é:
./myscript -flag flagvariable -otherflag flagvar2
Tudo o que você precisa fazer é editar a linha validflags. Anexa um hífen e pesquisa todos os argumentos. Em seguida, define o próximo argumento como o nome da bandeira, por exemplo
O código principal (versão curta, detalhada com exemplos mais abaixo, também uma versão com erro):
A versão detalhada com demos de eco integrados:
Final, este erro ocorre se um argumento inválido for passado.
Prós: O que faz, lida muito bem. Ele preserva argumentos não utilizados que muitas das outras soluções aqui não. Também permite que variáveis sejam chamadas sem serem definidas manualmente no script. Também permite a pré-população de variáveis se nenhum argumento correspondente for fornecido. (Veja exemplo detalhado).
Contras: Não é possível analisar uma única cadeia complexa de arg, por exemplo, -xcvf seria processada como um único argumento. Você poderia escrever com facilidade um código adicional no meu que adiciona essa funcionalidade.
fonte
Quero enviar meu projeto: https://github.com/flyingangel/argparser
Simples assim. O ambiente será preenchido com variáveis com o mesmo nome que os argumentos
fonte
Observe que
getopt(1)
foi um erro de curta duração da AT&T.O getopt foi criado em 1984, mas já foi enterrado em 1986 porque não era realmente utilizável.
Uma prova do fato de
getopt
estar muito desatualizado é que agetopt(1)
página de manual ainda menciona, em"$*"
vez de"$@"
, que foi adicionada ao Bourne Shell em 1986 junto com ogetopts(1)
shell interno para lidar com argumentos com espaços internos.BTW: se você estiver interessado em analisar opções longas em scripts de shell, pode ser interessante saber que a
getopt(3)
implementação da libc (Solaris) eksh93
ambas adicionaram uma implementação uniforme de opções longas que suporta opções longas como aliases para opções curtas. Isso faz com queksh93
eaBourne Shell
implementar uma interface uniforme para opções longas viagetopts
.Um exemplo de opções longas retiradas da página do manual Bourne Shell:
getopts "f:(file)(input-file)o:(output-file)" OPTX "$@"
mostra por quanto tempo os aliases de opções podem ser usados no Bourne Shell e no ksh93.
Veja a página de manual de um Bourne Shell recente:
http://schillix.sourceforge.net/man/man1/bosh.1.html
e a página de manual para getopt (3) do OpenSolaris:
http://schillix.sourceforge.net/man/man3c/getopt.3c.html
e, por último, a página do manual getopt (1) para verificar o $ * desatualizado:
http://schillix.sourceforge.net/man/man1/getopt.1.html
fonte
Eu escrevi um auxiliar de bash para escrever uma boa ferramenta de bash
página inicial do projeto: https://gitlab.mbedsys.org/mbedsys/bashopts
exemplo:
vai dar ajuda:
aproveitar :)
fonte
Aqui está a minha abordagem - usando o regexp.
-qwerty
-q -w -e
--qwerty
=
fornecer atributos, mas as correspondências de atributos até encontrar o hífen + espaço "delimitador", portanto, em--q=qwe ty
qwe ty
existe um atributo-o a -op attr ibute --option=att ribu te --op-tion attribute --option att-ribute
é válidoroteiro:
fonte
Suponha que criamos um script de shell chamado a
test_args.sh
seguirDepois de executarmos o seguinte comando:
A saída seria:
fonte
Use o módulo "argumentos" do bash-modules
Exemplo:
fonte
Misturando argumentos posicionais e baseados em sinalizadores
--param = arg (igual a delimitado)
Misturando livremente sinalizadores entre argumentos posicionais:
pode ser realizado com uma abordagem bastante concisa:
--param arg (delimitado por espaço)
É geralmente mais claro não misturar
--flag=value
e--flag value
estilos.É um pouco arriscado de ler, mas ainda é válido
Fonte
fonte
Aqui está um getopts que obtém a análise com código mínimo e permite definir o que você deseja extrair em um caso usando eval com substring.
Basicamente
eval "local key='val'"
Declara as variáveis como locais em vez de globais como a maioria das respostas aqui.
Chamado como:
O $ {k: 3} é basicamente uma substring para remover o primeiro
---
da chave.fonte
Também pode ser útil saber, você pode definir um valor e, se alguém fornecer entrada, substitua o padrão por esse valor.
myscript.sh -f ./serverlist.txt ou apenas ./myscript.sh (e assume os padrões)
fonte
Outra solução sem getopt [s], POSIX, antigo estilo Unix
Semelhante à solução que Bruno Bronosky publicou aqui é uma sem o uso de
getopt(s)
.O principal diferencial da minha solução é que ela permite concatenar opções da mesma forma que
tar -xzf foo.tar.gz
é igual atar -x -z -f foo.tar.gz
. E, assim como em etc.tar
,ps
o hífen principal é opcional para um bloco de opções curtas (mas isso pode ser alterado facilmente). Opções longas também são suportadas (mas quando um bloco começa com um, são necessários dois hífens principais).Código com opções de exemplo
Para o exemplo de uso, consulte os exemplos abaixo.
Posição das opções com argumentos
Pelo que vale a pena, as opções com argumentos não são as últimas (somente as opções longas precisam ser). Portanto, enquanto que, por exemplo, em
tar
(pelo menos em algumas implementações) asf
opções precisam ser as últimas, porque o nome do arquivo segue (tar xzf bar.tar.gz
funciona, mastar xfz bar.tar.gz
não funciona ), esse não é o caso aqui (veja os exemplos posteriores).Várias opções com argumentos
Como outro bônus, os parâmetros das opções são consumidos na ordem das opções pelos parâmetros com as opções necessárias. Basta olhar para a saída do meu script aqui com a linha de comando
abc X Y Z
(ou-abc X Y Z
):Opções longas concatenadas também
Também é possível ter opções longas no bloco de opções, uma vez que elas ocorrem pela última vez no bloco. Portanto, as seguintes linhas de comando são todas equivalentes (incluindo a ordem em que as opções e seus argumentos estão sendo processados):
-cba Z Y X
cba Z Y X
-cb-aaa-0-args Z Y X
-c-bbb-1-args Z Y X -a
--ccc-2-args Z Y -ba X
c Z Y b X a
-c Z Y -b X -a
--ccc-2-args Z Y --bbb-1-args X --aaa-0-args
Tudo isso leva a:
Não nesta solução
Argumentos opcionais
Opções com argumentos opcionais devem ser possíveis com um pouco de trabalho, por exemplo, observando se existe um bloco sem hífen; o usuário precisaria colocar um hífen na frente de cada bloco após um bloco com um parâmetro com um parâmetro opcional. Talvez isso seja muito complicado para se comunicar com o usuário; portanto, é necessário apenas um hífen principal neste caso.
As coisas ficam ainda mais complicadas com vários parâmetros possíveis. Eu desaconselharia a fazer as opções tentarem ser inteligentes, determinando se o argumento pode ser a favor ou não (por exemplo, com uma opção aceita apenas um número como argumento opcional), pois isso pode ser interrompido no futuro.
Pessoalmente, sou a favor de opções adicionais em vez de argumentos opcionais.
Argumentos de opção introduzidos com um sinal de igual
Assim como nos argumentos opcionais, eu não sou fã disso (BTW, existe um tópico para discutir os prós / contras de diferentes estilos de parâmetros?), Mas se você quiser isso, provavelmente poderá implementá-lo por conta própria, como feito em http: // mywiki.wooledge.org/BashFAQ/035#Manual_loop com um
--long-with-arg=?*
declaração de caso e, em seguida, retira o sinal de igual (este é o site que diz que fazer concatenação de parâmetros é possível com algum esforço, mas "o deixou como um exercício para o leitor "o que me fez acreditar na palavra deles, mas comecei do zero).Outras notas
Compatível com POSIX, funciona mesmo em configurações antigas do Busybox com as quais tive que lidar (com
cut
, por exemplo ,head
egetopts
ausente).fonte