De acordo com as Leis 12.965/2014 e 13.709/2018, que regulam o uso da Internet e o tratamento de dados pessoais no Brasil, ao me inscrever na newsletter do portal DICAS-L, autorizo o envio de notificações por e-mail ou outros meios e declaro estar ciente e concordar com seus Termos de Uso e Política de Privacidade.
Getopts - Opções em bash script
Colaboração: Fabiano Caixeta Duarte
Data de Publicação: 19 de Janeiro de 2006
Mais cedo ou mais tarde acabamos precisando de uma forma mais elaborada de
passar parâmetros (opções e argumentos) para nossos bash scripts.
No caso de um ou dois parâmetros, um case pode resolver para
testá-los. Entretanto, quando se trata de um conjunto maior de parâmetros,
principalmente quando envolvem opções com argumentos, entra em ação o comando
"embutido" getopts.
Nesta dica trago um script cuja finalidade é renomear um conjunto de imagens
(fotografias digitais, p. ex.), padronizando-as por meio de um prefixo. Este
será nosso exemplo prático da utilização de getopts.
Contextualização
Primeiramente vamos explicitar algumas coisas:
- Parâmetros: strings separadas por espaços, enviados ao script em sua
execução. No código a seguir, temos dois parâmetros passados ao script teste.sh
$ teste.sh dicas-l unicamp
$1 == dicas-l
$2 == unicamp
- Opções: caracteres precedidos do sinal - que servem para especificar quais funcionalidades do script serão utilizadas.
- Argumentos: são parâmetros das opções.
Neste outro exemplo vemos o uso de opções, com e sem argumentos, do ps - comando de listagem de processos.
$ ps -e -o pid
Como podemos observar, foram passadas duas opções (-e e -o), sendo que a opção -o recebeu o argumento 'pid'.
Assim como comandos e programas, scripts também podem receber opções e argumentos como parâmetros. Vejamos como utilizar o getopts para realizar o parsing, ou seja, separação e análise dos parâmetros passados a um script.
Getopts
O comando getopts trata apenas uma opção a cada chamada. Assim, se seu script espera mais de uma opção, ele deverá conter mais de uma chamada do getopts. A maneira mais fácil de fazer isto é chamá-lo em um loop while. Isto porque o getopts retorna false após o parsing de todos os parâmetros passados.
Outra questão importante é a maneira como informamos ao getopts se uma opção deve ou não exigir argumentos. Isto é obtido da seguinte maneira:
while getopts "hf:t:" OPT; do
(commands)
done
Traduzindo para o português, o código acima quer dizer:
- São aceitas três opções: h f t
- As opções 'f' e 't' exigem argumentos. Note o uso do caracter ':'.
- A opção em análise fica armazenada na variável OPT.
Para tratar cada opção passada, podemos fazer o uso do case, analisando o conteúdo da variável OPT.
while getopts "hf:t:" OPT; do
case "$OPT" in
"h") usage;; # exibir ajuda
"f") FROM=$OPTARG;;
"t") TO=$OPTARG;;
"?") exit -1;;
esac
done
Surgiram duas novidades aí!!!
- A variável OPTARG recebe o argumento da opção em análise
- Quando uma opção inesperada for passada como parâmetro, a variável utilizada para armazenar a opção (no caso, OPT) recebe o valor '?'. É assim que tratamos erro no getopts :)
O brinde
Conforme prometido, aí vai o brinde da dica para servir de exemplo prático de utilização.
#!/bin/bash
########
#
# This script is used to rename a set of photos with a given prefix
# like birthday-001.jpg birthday-002.jpg and so on
#
# Created and mainteined by Fabiano Caixeta Duarte <fcd@superig.com.br>
#
########
THIS=$(basename $0)
function usage() {
echo -e "$THIS 0.1\t-\tAuthor: Fabiano Caixeta Duarte <fcd@superig.com.br>"
echo "
Usage:
$THIS -i <image type> [-c <counter_starter>] -f <from_prefix> -t <to_prefix>
$THIS -h (shows this help)
"
exit -1
}
while getopts "hi:c:f:t:" OPT; do
case $OPT in
"h") usage;;
"i") IMGTYPE=$OPTARG;;
"c") COUNTER=$OPTARG; [[ $COUNTER =~ ^[0-9]{1,3}$ ]] || usage;;
"f") FROM=$OPTARG
for F in ${FROM}*.${IMGTYPE}; do
[ ! -f $F ] && echo "$THIS: $FROM*.$IMGTYPE not found" && exit -2
done;;
"t") TO=$OPTARG;;
"?") exit -2;;
esac
done
[ -z "$FROM" -o -z "$TO" -o -z "$IMGTYPE" ] && usage
let ${COUNTER:=1}
for FILE in ${FROM}*.${IMGTYPE}; do
mv -v $FILE $(printf "%s%03d.%s" $TO $COUNTER $IMGTYPE)
((COUNTER++))
done
exit 0
Conclusão
O bash possui um comando built-in chamado getopts que pode ser utilizado no seguinte contexto:
- você precisa passar vários parâmetros para seu script
- nem todos os parâmetros são utilizados conjuntamente
- estes parâmetros consistem em opções que dependem de argumentos