Português do Brasil English
Devin no Facebook  Devin no Twitter  RSS do Site 
Programação    

Shell Script: tratamento de argumentos e opções


Comentários  9
Visualizações  
232,083

Na grande maioria das vezes, a linguagem shell script é usada para criar uma sequência de comandos que automatizam uma tarefa. Nisso, ela é extremamente eficiente e rápida. Combinar comandos é uma grande vantagem que o jeito UNIX de ser nos trouxe: várias ferramentas que fazem tarefas básicas, especializadas, e que quando se juntam realizam grandes feitos trabalhando juntas. Mas isso nunca impediu que se criasse também programas completos em shell script.

Uma característica para deixar um shell-script mais robusto e menos “sequencial/batch-mode” é o tratamento de argumentos. No meu clássico tutorial Programando em Shell-Script, o tópico Variáveis Especiais nos traz os primeiros itens que devemos aprender para o tratamento de argumentos. Existem variáveis especiais que tratam os argumentos passados para um programa ou uma função. Estes são:

  • $0 – Retorna o nome do script que foi executado
  • $N – Onde N é um número, corresponde ao argumento passado (1 = primeiro argumento, 2 = segundo argumento, 3 = terceiro argumento, etc)
  • $* – Retorna todos os argumentos de uma vez.
  • $# – Retorna a quantidade de argumentos passado para o script. (argc)

Vejamos agora um shell-script exempo que faz uso de todos esses argumentos:

#!/bin/bash

if [ $# -lt 1 ]; then
   echo "Faltou utilizar pelo menos um argumento!"
   exit 1
fi

echo "Numero de argumentos: $#"

COUNT=0
for ARG in $*; do
   COUNT=`expr $COUNT + 1`
   echo "Argumento $COUNT: $ARG"
done

As linhas 3 a 6 verificam se a quantidade de argumentos ($#) é menor (-lt – less than) que 1. Ou seja, se o usuário não chamou o programa com nenhum argumento, ele imprime um erro e sai do programa com status 1.

A linha 8 mostra quantos argumentos foram utilizados, usando novamente o $#.

O resto das linhas, 10 a 14, usam o $* com um laço for e um contador para mostrar quais foram os argumentos.

Executando agora este script sem argumentos:

$ ./tmp.sh
Faltou utilizar pelo menos um argumento!

Agora executando com dois argumentos:

$ ./tmp.sh naosei testando
Numero de argumentos: 2
Argumento 1: naosei
Argumento 2: testando

E agora com 4 argumentos:

$ ./tmp.sh a b c d
Numero de argumentos: 4
Argumento 1: a
Argumento 2: b
Argumento 3: c
Argumento 4: d

Bem simples né?

Argumentos como opções e seus valores

Algo comum que vemos nos programas são opções. Opções não deixam de ser argumentos para um programa, mas eles tem um significado especial. Do tipo: Se a opção -d existir, ativar durante o programa o modo de depuração. Se houver um -h, então mostre uma ajuda e não faça mais nada. Se houver um -v mostre a versão, e por aí vai.

Exemplo:

#!/bin/bash

case $1 in
   "-h") echo "Isto seria uma ajuda... Mas fiquei com preguiça de escrevê-la."
         ;;
   "-v") echo "Versão 666."
         ;;
   *) echo "Opção inválida!"
      exit 1
      ;;
esac

Exemplos do uso do script:

$ ./tmp.sh -h
Isto seria uma ajuda... Mas fiquei com preguiça de escrevela.

$ ./tmp.sh -v
Versão 666.

$ ./tmp.sh -O
Opção inválida!

$ ./tmp.sh
Opcao invalida!

Com isso a gente resolve um problema e cria mais outros dois…

  • E se o usuário colocar as duas opções? Só uma funcionaria.
  • E se uma das opções precisasse de um valor? Estilo “-f arquivo.log” gravaria um arquivo de log com as operações.

Poderíamos escrever vários algoritmos que verificassem cada um de todos os argumentos, testasse se fosse um ou outro, utilizasse as opções… Mas felizmente não precisamos fazer nada disso! O bash conta com uma função interna que trata os argumentos: o famoso getopts.

Utilizando o getopts para tratar tratar argumentos e opções

Seguindo a mesma linha de raciocínio, vamos logo para um exemplo de programa. Supondo que queiramos um shell-script que faça isso:

  • Caso a opção -h seja usada, mostra a ajuda e sai do programa.
  • Caso a opção -v seja usada, mostra a versão e sai do programa.
  • Caso a opção -o seja usada, grava um arquivo de log com as operações efetuadas e resultados.
  • Caso a opção -u seja usada, mostra o resultado do comando “uname -a”
  • Caso a opção -m seja usada, mostra o resultado do comando “free -m”
  • Caso a opção -s seja usada, mostra o resultado do comando “swap -s”

Note que apenas as opções -h e -v saem do programa após a execução. Agora vamos ao código:

#!/bin/bash

function PrintUsage() {
   echo "Uso: `basename $0` <-umsf> [-ohv]"
   exit 1
}

while getopts "hvo:umsf" OPTION
do
   case $OPTION in
      h) PrintUsage
         ;;
      v) echo "`basename $0` versao 666."
         exit
         ;;
      o) ARQUIVO_LOG=$OPTARG
         ;;
      u) DO_UNAME=1
         ;;
      m) DO_FREE=1
         ;;
      s) DO_SWAPON=1
         ;;
      ?) PrintUsage
         ;;
   esac
done
shift $((OPTIND-1))

if [ -z "$DO_UNAME" ] && [ -z "$DO_FREE" ] && [ -z "$DO_SWAPON" ] && [ -z "$DO_FDISK" ]; then
   PrintUsage
fi

if [ "$ARQUIVO_LOG" ]; then   echo "Execucao iniciada em `date`." >> $ARQUIVO_LOG

   if [ "$DO_UNAME" == 1 ]; then
      uname -a >> $ARQUIVO_LOG
   fi

   if [ "$DO_FREE" == 1 ]; then
      free -m >> $ARQUIVO_LOG
   fi

   if [ "$DO_SWAPON" == 1 ]; then
      swapon -s >> $ARQUIVO_LOG
   fi
else
   echo "Execucao iniciada em `date`."
   if [ "$DO_UNAME" == 1 ]; then
      uname -a
   fi

   if [ "$DO_FREE" == 1 ]; then
      free -m
   fi

   if [ "$DO_SWAPON" == 1 ]; then
      swapon -s
   fi
fi

O interessante para nós são as linhas 8 a 28. O laço while getopts começa a tratar todos os argumentos. A cada iteração do laço, ele coloca a letra da opção na variável $OPTION.

Note que para cada opção que precisamos, colocamos uma letra no primeiro argumento do getopts:

while getopts "hvo:umsf" OPTION

Note também que depois da letra o temos um dois pontos (:). Esse dois pontos significa que logo após a opção -o, o usuário precisa fornecer um valor. Este valor é automaticamente armazenado na variável $OPTARG.

Dessa maneira, podemos executar esse programa de diversas formas:

./tmp.sh -o arquivo.log -u
(executa o "uname -a" e grava no arquivo arquivo.log)

./tmp.sh -um
(executa os comandos "uname -a" e "free -m")

./tmp.sh -m -s -u
(executa os comandos "free -m", "swapon -s" e "uname -a")

Ou seja, não importa a ordem, o getopts vai reconhecer e executar as ações de acordo com a opção especificada.

E se você colocar uma opção que não está contemplatada… O “?” do case irá ser executado, por exemplo:

$ ./tmp.sh -a
./tmp.sh: illegal option -- a
Uso: tmp.sh <-umsf> [-ohv]

E dessa forma fica bem fácil de entender e usar o getopts :) Depois que o laço é todo feito e executado em todos os argumentos (no meu caso, preferi apenas configurar variáveis para cada opção e tratá-las depois), ele executa o comando que está na linha 28:

shift $((OPTIND-1))

Este comando faz com que os argumentos de opções sejam “comidos“, até que não sobre nenhuma opção. Em outras palavras, os argumentos representados pelas variáveis $N só serão aqueles que não pertençam a nenhuma opção. Exemplo:

./tmp.sh -u -o arquivo.log -m argumento1 argumento2

Nesse caso, o $1 seria o argumento1 e o $2 seria o argumento2, quando na verdade, sem o shift, eles seriam respectivamente o $5 e $6.

Como nem tudo é perfeito, a função getopts do bash não aceita opções longas (–nome-da-opcao), ou seja, voce só pode utilizar uma letra como opção. Represente bem suas opções com as letras! :)

Argumentos dentro de funções

Se dentro de um shell-script temos uma função, essa função é enxergada pela shell como se fosse um comando. Nesse sentido, dentro de uma função as variáveis $N definidas pelo programa não funcionarão. Exemplo:

#!/bin/bash

function Dummy() {
   echo "Numero de argumentos: $#"

   COUNT=0
   for ARG in $*; do
      COUNT=`expr $COUNT + 1`
      echo "Argumento $COUNT: $ARG"
   done
}

Dummy

Não importa o que você executar com o script acima, a saída será sempre a mesma: 0 números de argumentos, como mostrado a seguir.

$ ./tmp.sh
Numero de argumentos: 0

$ ./tmp.sh naosei temporario
Numero de argumentos: 0

$ ./tmp.sh a b c d e f g
Numero de argumentos: 0

Para a função Dummy, as variáveis especiais dos argumentos funcionam apenas para a função e não para o programa inteiro. É como se as variáveis fossem locais, e não globais. Vamos então substituir a linha da chamada da função Dummy (linha 13) por:

Dummy a b c d

E tentar executar novamente:

$ ./tmp.sh
Numero de argumentos: 4
Argumento 1: a
Argumento 2: b
Argumento 3: c
Argumento 4: d

Sabendo disso, não se percam na hora de usar os argumentos dentro das funções e lembrem-se que isto pode ser útil na hora de implementar diversas funções dentro de um script. Um bom exemplo disso é implementar a função PrintUsage que usamos anteriormente para, além de mostrar uma mensagem de uso, mostrar também uma mensagem de erro personalizada:

function PrintUsage() {
   [ "$1" ] && echo -ne "Erro: $1\n"
   echo "Uso: $(basename $0)  <-umsf> [-ohv]"
   exit 1
}

Agora é so chamar a função como…

PrintUsage "Faltando parâmetros."
PrintUsage "Opção inválida."
PrintUsage "No donut for you."

Use a criatividade de um programador (afinal, programação é arte) e comece a aprimorar suas ferramentas bash! :)


Comentários  9
Visualizações  
232,083


TagsLeia também

Apaixonado por Linux e administração de sistemas. Viciado em Internet, servidores, e em passar conhecimento. Idealizador do Devin, tem como meta aprender e ensinar muito Linux, o que ele vem fazendo desde 1997 :-)


Leia também



Comentários

9 respostas para “Shell Script: tratamento de argumentos e opções”

  1. Victor Farias disse:

    cara sempre tive essa duvida, vlw

  2. Fabio Parada disse:

    Gostaria de saber qual editor voce usa nos scripts, gostei muito da tela com os exemplos acima, se der me passe o nome do Editor e onde baixar.

    Parabens pelo site .

    Abraco

    Fabio Parada

  3. Eduardo Colabardini disse:

    Muito interessante esse tratamento de argumentos com o getopts, realmente amazing. Obrigado.

  4. felipe disse:

    excelente guia,ajudou-me Muito!obrigado!

  5. [...] Vejamos agora um shell-script exempo que faz uso de todos esses argumentos: view source print? [...]

  6. no painel do meu site tem esse Shell Script

    Tem como eu usar ele para tirar Backup dos e-email do meu site

    tipo sempre tenho que trocar a hospedagem de varios site tirando backup dos e-mail 1 a 1

    tem como fazer isso automaticamente por esse painel Shell que tem no CPANEL

    ou eu to falando Besteira e viajei

  7. charlene disse:

    Tem como eu usar como entrada um programa em c por exembro (soma.c) e fazer que ela seja compilada pelo gcc atravez de um script…ele manda esse programa ser compilado pelo gcc e mostra o resultado

  8. Additionally, there are two metal bracelets offered, and those are usually 648 with no VAT (about $736). Whilst visually it may seem like you’d probably want it knocked a little more for the edge from the dial, they have place in a means that does not cut-off the indice found right now there, which is a great touch. Gumball 3000 was developed in 1999 simply by ex-racing motorist, designer plus British business owner Maximillion Cooper who a new vision to mix cars, songs, fashion plus entertainment to produce a lifestyle occasion that happens once each year. Well, gowns always the particular toughest query. The call of this Swarovski Lovely Deposits watches is definitely mother-of-pearl and it is surrounded simply by another band of deposits. Again, there is not inherently anything at all new, but instead a new taste – that is exactly how Panerai prefers this. Yes, I believe so. Energy reserve is definitely 48-hours. Instead, the LM54 caliber, constructed for Louis Moinet by way of a movement producer Concept, continues to be specially designed so the traditional operation of the automated mechanism are usually hidden aside on the back again of the motion, beneath the dish, leaving only the chronograph system exposed for the dial. The particular reference 912. ND. 0123. RX Hublot MP-12 Crucial Of Time Skeletal system watches is restricted to twenty pieces and it is priced at $288, 000. This particular watches stands apart immediately because of its retro-styling plus eye-catching call that features a unique chronograph size. Each time I realize the “singing bird action” in operation We quickly create a smile upon my encounter. Frankly, which is overall develop of the timepieces for me — it simply looks great. Retail cost is $3, 250 (production is not limited). And while the particular rigth part of the call is artisticthe left part is more centered on the motion, revealing the particular beating center of the timepieces as well as the off-centered seconds. Girard-Perregaux have had achievement with a lots of the exterior components within this watches, yet it’s the motion that shop lifts the display. The shape through the side proceeds the soft modern really feel, as it lightly curves right down to contour towards the wrist. Lately, TokyoFlash actually seems to be right into a sort of seventies SciFi kind of a theme, mixing wooden (for the situation and bracelet) with slanted shapes plus vivid DIRECTED displays.
    perfectjewelrys.com http://www.perfectjewelrys.com/

Deixe uma resposta