Estou confuso sobre como incluir argumentos / sinalizadores opcionais ao escrever um script bash para o seguinte programa:
O programa requer dois argumentos:
run_program --flag1 <value> --flag2 <value>
No entanto, existem vários sinalizadores opcionais:
run_program --flag1 <value> --flag2 <value> --optflag1 <value> --optflag2 <value> --optflag3 <value> --optflag4 <value> --optflag5 <value>
Eu gostaria de executar o script bash de forma que ele receba argumentos do usuário. Se os usuários digitarem apenas dois argumentos em ordem, seria:
#!/bin/sh
run_program --flag1 $1 --flag2 $2
Mas e se algum dos argumentos opcionais for incluído? Eu pensaria que seria
if [ --optflag1 "$3" ]; then
run_program --flag1 $1 --flag2 $2 --optflag1 $3
fi
Mas e se $ 4 forem dados, mas não $ 3?
shell-script
arguments
ShanZhengYang
fonte
fonte
getopts
é o que você quer. Sem isso, você pode usar um loop com uma instrução switch para detectar cada sinalizador, opcional ou não.getopts
, eu precisaria especificar cada combinação de argumentos? 3 e 4, 3 e 5, 3 e 4 e 5, etc.?getopts
. Digamos que eu force os usuários a executar o script com todos os argumentos:run_program.sh VAL VAL FALSE FALSE FALSE FALSE FALSE
que executa o programa comoprogram --flag1 VAL --flag2 VAL
. Se você executourun_program.sh VAL VAL FALSE 10 FALSE FALSE FALSE
, o programa seria executado comoprogram --flag1 VAL --flag2 VAL --optflag2 10
. Como você pode obter esse comportamentogetopts
?Respostas:
Este artigo mostra duas maneiras diferentes -
shift
egetopts
(e discute as vantagens e desvantagens das duas abordagens).Com o
shift
seu script$1
, ele decide qual ação executar e, em seguidashift
, executa , movendo$2
para$1
,$3
para$2
etc.Por exemplo:
Com
getopts
você, defina as opções (curtas) nawhile
expressão:Obviamente, esses são apenas trechos de código e deixei de lado a validação - verificando se os argumentos obrigatórios flag1 e flag2 estão definidos, etc.
Qual abordagem você usa é, até certo ponto, uma questão de gosto - quão portátil você deseja que seu script seja, se você pode viver apenas com opções curtas (POSIX) ou se deseja opções longas (GNU) etc.
fonte
while (( $# ))
vez de,while :;
e muitas vezes desisto, com um erro no*
casoset -o nounset
primeira solução, ocorrerá um erro se nenhum parâmetro for fornecido. Correção:case ${1:-} in
use uma matriz.
isso manipulará argumentos com espaços neles corretamente.
[edit] Eu estava usando a sintaxe aproximadamente equivalente,
args=( "${args[@]}" --optflag1 "$3" )
mas o G-Man sugeriu uma maneira melhor.fonte
args+=( --optflag1 "$3" )
. Você pode querer ver minha resposta ao nosso trabalho de referência, Implicações de segurança de não citar uma variável nos shells bash / POSIX , onde discuto essa técnica (de construção de uma linha de comando em uma matriz anexando condicionalmente argumentos opcionais).[@]
que tinha uma ferramenta suficiente para resolver meu problema.Em um script de shell, os argumentos são "$ 1", "$ 2", "$ 3" etc. O número de argumentos é $ #.
Se o seu script não reconhecer opções, você pode deixar de fora a detecção de opções e tratar todos os argumentos como operandos.
Para reconhecer opções, use as getopts internas
fonte
Se suas opções de entrada são posicionais (você sabe em que lugares eles estão) e não são especificadas com sinalizadores, o que você deseja é apenas construir a linha de comando. Basta preparar os argumentos de comando para todos eles:
Se os parâmetros não forem especificados, as seqüências correspondentes estarão vazias e se expandirão em nada. Observe que na última linha, não há aspas. Isso porque você deseja que o shell divida os parâmetros em palavras (para fornecer
--flag1
e$1
como argumentos separados para o seu programa). Obviamente, isso dará errado se seus parâmetros originais contiverem espaços. Se você é quem está executando isso, pode deixá-lo, mas se for um script geral, ele poderá ter um comportamento inesperado se o usuário inserir algo com espaços. Para lidar com isso, você precisará tornar o código um pouco mais feio.O
x
prefixo no[]
teste está lá$3
ou$4
está vazio. Nesse caso, o bash se expandirá[ FALSE != $3 ]
para o[ FALSE != ]
que é um erro de sintaxe, então outro caractere arbitrário existe para se proteger contra isso. Essa é uma maneira muito comum, você a verá em muitos scripts.Eu configurei
OPTFLAG1
e o restante deles""
no início apenas para ter certeza (no caso de eles terem sido configurados para algo antes), mas se eles não foram realmente declarados no ambiente, você não precisa fazer isso estritamente.Algumas observações adicionais:
runprogram
: com sinalizadores. É disso queJohn N
se trata. É aí quegetopts
se torna útil.-
) para sinalizar um valor vazio, ou apenas passasse uma string vazia, como""
, se isso não for um valor válido do parâmetro. String vazia também torna o teste mais curto, basta usarif [ -n "$3" ]
.""
parâmetros vazios, como sugerido acima, poderá pular todos os vazios finais de qualquer maneira.Esse método é basicamente o modo como as opções são passadas para os compiladores no Makefiles.
E novamente - se as entradas podem conter espaços, fica feio.
fonte