getopts: Analisando Opções de Linha de Comando no Bash
O Que Você Vai Aprender
- Como analisar argumentos de opção como
-ae-b valorem scripts shell de forma segura - O papel e a sintaxe de
getoptsoptstring/OPTARG/OPTIND - Como tratar opções inválidas e argumentos ausentes por conta própria (modo silencioso)
- Quando usar
getopts(builtin do shell) vsgetopt(comando externo)
Resumo Rápido
- Prefira
getoptsem vez de análise manual (POSIX, portável) - O loop principal e
while getopts ":a:bc" opt; do ... done - Opções que recebem argumento são declaradas como
letra:na optstring (a:) - Após o loop, execute
shift $((OPTIND - 1))para alcançar os argumentos posicionais restantes
Premissas (ambiente alvo)
- bash / POSIX sh (
getoptsé um builtin) - Apenas opções curtas (
-a,-v) são suportadas. Opções longas como--verbosenão são.
O Que é getopts?
Conclusão: getopts é um builtin do shell para análise de opções; combinado com um loop while, ele extrai argumentos
-a/-b valorum de cada vez.
getopts é um builtin do shell que analisa opções de linha de comando (argumentos curtos com -) uma de cada vez. Em vez de desmontar $1 e $2 manualmente com uma instrução case, você obtém uma forma padronizada de processar opções.
A sintaxe básica é:
getopts optstring name [args]
optstring: o conjunto de letras de opção válidas (ex.:"abc"significa-a-b-c)name: a variável que recebe a letra da opção detectada- Cada chamada processa uma opção, retornando status de saída 0 (verdadeiro) enquanto houver opções restantes
Esse comportamento de "retorna verdadeiro enquanto houver opções" é exatamente o que um loop while precisa.
Por que usar getopts em vez de análise manual?
Conclusão: getopts trata opções agrupadas (
-abc) e o terminador--de acordo com o padrão, algo que instruções case escritas manualmente tendem a ignorar.
Crie seu próprio while [ $# -gt 0 ] com case "$1" in e você acabará reimplementando cada regra sutil por conta própria:
- Opções agrupadas: permitir que
-a -b -cseja escrito como-abc - Opções com argumentos: aceitar tanto
-b valorquanto-bvalor - O terminador
--: parar de tratar tudo depois dele como opções - Detectar opções inválidas e argumentos ausentes
getopts trata tudo isso com comportamento padrão POSIX. É portável e evita sintaxe exclusiva do bash, funcionando sem alterações em um script #!/bin/sh.
Se opções longas (--output file) não são um requisito obrigatório, use getopts primeiro. O código é mais curto e o comportamento é padronizado.
Como usar getopts?
Conclusão: Declare as letras aceitas na optstring, adicione
:às letras que recebem argumento; OPTARG armazena o valor e OPTIND o próximo índice.
Escrevendo a optstring
A optstring é uma string de letras de opção aceitas. Adicione : a uma letra que recebe argumento.
| optstring | Significado |
|---|---|
"abc" |
-a -b -c (sem argumentos) |
"a:bc" |
-a recebe argumento; -b -c não recebem |
":a:bc" |
: inicial habilita modo silencioso (abaixo) |
Template básico
#!/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 execução:
$ ./script.sh -v -o result.txt input1 input2
verbose=1 output=result.txt Remaining arguments: input1 input2
OPTARG e OPTIND
getopts atualiza duas variáveis automaticamente durante a análise.
OPTARG: o valor do argumento de uma opção que recebe um (o:). Acima, éresult.txtde-o result.txt.OPTIND: o índice do próximo argumento a processar. Começa em1. Após o loop, aponta para o primeiro argumento que não é opção.
Executar shift $((OPTIND - 1)) após o loop remove todas as opções processadas, deixando apenas os argumentos que não são opções (nomes de arquivo, etc.) em $1 em diante.
OPTIND é inicializado como 1 quando o shell inicia. Em uma função que executa o loop getopts mais de uma vez no mesmo shell, reinicie OPTIND=1 antes do loop ou a segunda passagem se comportará incorretamente.
Como tratar erros?
Conclusão: Um
:inicial na optstring habilita o modo silencioso; opções inválidas colocam?em name, argumentos ausentes colocam:, e OPTARG armazena a letra infratora.
getopts tem dois modos de relato de erros.
Modo normal (optstring não começa com :)
Em uma opção inválida ou argumento ausente, getopts imprime uma mensagem no erro padrão por conta própria e armazena ? em name. Conveniente, mas você não pode controlar o texto.
Modo silencioso (optstring começa com :)
Inicie a optstring com um : inicial (ex.: ":vo:") e getopts não imprime mensagem, permitindo que seu script trate cada erro. O comportamento é:
| Situação | Valor em name |
Valor em OPTARG |
|---|---|---|
| Opção inválida | ? |
o caractere infrator |
| Argumento ausente | : |
a letra da opção 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 prática. Você obtém controle total da saída para o usuário: localizar mensagens, chamar uma função usage() e encerrar de forma limpa.
Como getopts difere de getopt?
Conclusão: getopts é um builtin apenas para opções curtas; se você precisa de opções longas como
--verbose, use o getopt externo (util-linux).
Eles diferem por uma letra, mas são ferramentas diferentes.
| Aspecto | getopts (builtin) |
getopt (externo) |
|---|---|---|
| O que é | Builtin do shell | /usr/bin/getopt (util-linux, etc.) |
| Opções longas | Não (-a apenas) |
Sim (--all) |
| Portabilidade | Alta, padrão POSIX | Varia (versão GNU aprimorada pode ser necessária) |
| Uso | Busca uma de cada vez no loop | Reordena todos os args, depois analisa |
Se opções curtas são suficientes, use getopts; se opções no estilo --output são um requisito, considere getopt (a versão GNU aprimorada).
Existe um truque para tratar opções longas apenas com getopts (tratar - como uma opção que recebe argumento e reanalisar OPTARG), mas isso prejudica a legibilidade. Quando o requisito é firme, o getopt puro é mais fácil de manter.
Quais são as armadilhas comuns?
Conclusão: Esquecer de reiniciar OPTIND, esquecer o shift e passar opções longas são os três clássicos.
1. Não reiniciar OPTIND dentro de uma função
Usar getopts em uma função 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 opção, quebrando o tratamento de arquivos posterior. Sempre execute logo após o loop.
3. Passar opções longas
Passe --verbose para getopts e ele interpretará cada caractere após - (-, v, e...) como uma opção separada, causando comportamento indesejado. Se você precisa de opções longas, escolha getopt na fase de projeto.
Resumo
getopts implementa a análise de opções do shell de forma padronizada e portável como builtin. Memorize a forma while getopts ":a:bc" opt; do case ... done, trate erros por conta própria no modo silencioso (: inicial) e finalize com shift $((OPTIND - 1)) para alcançar os argumentos posicionais -- domine esses três pontos e você estará pronto para scripts do mundo real.