getopts: Analisando Opcoes de Linha de Comando no Bash
O Que Voce Vai Aprender
- Como analisar argumentos de opcao como
-ae-b valorem scripts shell de forma segura - O papel e a sintaxe de
getoptsoptstring/OPTARG/OPTIND - Como tratar opcoes invalidas e argumentos ausentes por conta propria (modo silencioso)
- Quando usar
getopts(builtin do shell) vsgetopt(comando externo)
Resumo Rapido
- Prefira
getoptsem vez de analise manual (POSIX, portavel) - O loop principal e
while getopts ":a:bc" opt; do ... done - Opcoes que recebem argumento sao declaradas como
letra:na optstring (a:) - Apos o loop, execute
shift $((OPTIND - 1))para alcancar os argumentos posicionais restantes
Premissas (ambiente alvo)
- bash / POSIX sh (
getoptse um builtin) - Apenas opcoes curtas (
-a,-v) sao suportadas. Opcoes longas como--verbosenao sao.
O Que e getopts?
Conclusao: getopts e um builtin do shell para analise de opcoes; combinado com um loop while, ele extrai argumentos
-a/-b valorum de cada vez.
getopts e um builtin do shell que analisa opcoes de linha de comando (argumentos curtos com -) uma de cada vez. Em vez de desmontar $1 e $2 manualmente com uma instrucao case, voce obtem uma forma padronizada de processar opcoes.
A sintaxe basica e:
getopts optstring name [args]
optstring: o conjunto de letras de opcao validas (ex.:"abc"significa-a-b-c)name: a variavel que recebe a letra da opcao detectada- Cada chamada processa uma opcao, retornando status de saida 0 (verdadeiro) enquanto houver opcoes restantes
Esse comportamento de "retorna verdadeiro enquanto houver opcoes" e exatamente o que um loop while precisa.
Por que usar getopts em vez de analise manual?
Conclusao: getopts trata opcoes agrupadas (
-abc) e o terminador--de acordo com o padrao, algo que instrucoes case escritas manualmente tendem a ignorar.
Crie seu proprio while [ $# -gt 0 ] com case "$1" in e voce acabara reimplementando cada regra sutil por conta propria:
- Opcoes agrupadas: permitir que
-a -b -cseja escrito como-abc - Opcoes com argumentos: aceitar tanto
-b valorquanto-bvalor - O terminador
--: parar de tratar tudo depois dele como opcoes - Detectar opcoes invalidas e argumentos ausentes
getopts trata tudo isso com comportamento padrao POSIX. E portavel e evita sintaxe exclusiva do bash, funcionando sem alteracoes em um script #!/bin/sh.
Se opcoes longas (--output file) nao sao um requisito obrigatorio, use getopts primeiro. O codigo e mais curto e o comportamento e padronizado.
Como usar getopts?
Conclusao: Declare as letras aceitas na optstring, adicione
:as letras que recebem argumento; OPTARG armazena o valor e OPTIND o proximo indice.
Escrevendo a optstring
A optstring e uma string de letras de opcao aceitas. Adicione : a uma letra que recebe argumento.
| optstring | Significado |
|---|---|
"abc" |
-a -b -c (sem argumentos) |
"a:bc" |
-a recebe argumento; -b -c nao recebem |
":a:bc" |
: inicial habilita modo silencioso (abaixo) |
Template basico
#!/bin/bash
verbose=0
output=""
while getopts "vo:" opt; do
case "$opt" in
v) verbose=1 ;;
o) output="$OPTARG" ;;
\?) echo "Unknown option: -$OPTARG" >&2; exit 1 ;;
esac
done
shift $((OPTIND - 1))
echo "verbose=$verbose output=$output"
echo "Remaining arguments: $*"Exemplo de execucao:
$ ./script.sh -v -o result.txt input1 input2
verbose=1 output=result.txt Remaining arguments: input1 input2
OPTARG e OPTIND
getopts atualiza duas variaveis automaticamente durante a analise.
OPTARG: o valor do argumento de uma opcao que recebe um (o:). Acima, eresult.txtde-o result.txt.OPTIND: o indice do proximo argumento a processar. Comeca em1. Apos o loop, aponta para o primeiro argumento que nao e opcao.
Executar shift $((OPTIND - 1)) apos o loop remove todas as opcoes processadas, deixando apenas os argumentos que nao sao opcoes (nomes de arquivo, etc.) em $1 em diante.
OPTIND e inicializado como 1 quando o shell inicia. Em uma funcao que executa o loop getopts mais de uma vez no mesmo shell, reinicie OPTIND=1 antes do loop ou a segunda passagem se comportara incorretamente.
Como tratar erros?
Conclusao: Um
:inicial na optstring habilita o modo silencioso; opcoes invalidas colocam?em name, argumentos ausentes colocam:, e OPTARG armazena a letra infratora.
getopts tem dois modos de relato de erros.
Modo normal (optstring nao comeca com :)
Em uma opcao invalida ou argumento ausente, getopts imprime uma mensagem no erro padrao por conta propria e armazena ? em name. Conveniente, mas voce nao pode controlar o texto.
Modo silencioso (optstring comeca com :)
Inicie a optstring com um : inicial (ex.: ":vo:") e getopts nao imprime mensagem, permitindo que seu script trate cada erro. O comportamento e:
| Situacao | Valor em name |
Valor em OPTARG |
|---|---|---|
| Opcao invalida | ? |
o caractere infrator |
| Argumento ausente | : |
a letra da opcao que precisava de um |
Tratamento de erros no modo silencioso:
while getopts ":vo:" opt; do
case "$opt" in
v) verbose=1 ;;
o) output="$OPTARG" ;;
\?) echo "Unknown option: -$OPTARG" >&2; exit 1 ;;
:) echo "Option -$OPTARG requires an argument" >&2; exit 1 ;;
esac
donePrefira o modo silencioso na pratica. Voce obtem controle total da saida para o usuario: localizar mensagens, chamar uma funcao usage() e encerrar de forma limpa.
Como getopts difere de getopt?
Conclusao: getopts e um builtin apenas para opcoes curtas; se voce precisa de opcoes longas como
--verbose, use o getopt externo (util-linux).
Eles diferem por uma letra, mas sao ferramentas diferentes.
| Aspecto | getopts (builtin) |
getopt (externo) |
|---|---|---|
| O que e | Builtin do shell | /usr/bin/getopt (util-linux, etc.) |
| Opcoes longas | Nao (-a apenas) |
Sim (--all) |
| Portabilidade | Alta, padrao POSIX | Varia (versao GNU aprimorada pode ser necessaria) |
| Uso | Busca uma de cada vez no loop | Reordena todos os args, depois analisa |
Se opcoes curtas sao suficientes, use getopts; se opcoes no estilo --output sao um requisito, considere getopt (a versao GNU aprimorada).
Existe um truque para tratar opcoes longas apenas com getopts (tratar - como uma opcao que recebe argumento e reanalisar OPTARG), mas isso prejudica a legibilidade. Quando o requisito e firme, o getopt puro e mais facil de manter.
Quais sao as armadilhas comuns?
Conclusao: Esquecer de reiniciar OPTIND, esquecer o shift e passar opcoes longas sao os tres classicos.
1. Nao reiniciar OPTIND dentro de uma funcao
Usar getopts em uma funcao carrega o valor anterior de OPTIND. Adicione local OPTIND (ou OPTIND=1) antes do loop.
parse_args() {
local OPTIND # local da funcao, reinicia a cada chamada
while getopts ":vo:" opt; do
# ...
done
}2. Esquecer o shift e desalinhar argumentos posicionais
Pule shift $((OPTIND - 1)) e $1 permanece como uma string de opcao, quebrando o tratamento de arquivos posterior. Sempre execute logo apos o loop.
3. Passar opcoes longas
Passe --verbose para getopts e ele interpretara cada caractere apos - (-, v, e...) como uma opcao separada, causando comportamento indesejado. Se voce precisa de opcoes longas, escolha getopt na fase de projeto.
Resumo
getopts implementa a analise de opcoes do shell de forma padronizada e portavel como builtin. Memorize a forma while getopts ":a:bc" opt; do case ... done, trate erros por conta propria no modo silencioso (: inicial) e finalize com shift $((OPTIND - 1)) para alcancar os argumentos posicionais -- domine esses tres pontos e voce estara pronto para scripts do mundo real.