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:
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:
Agora executando com dois argumentos:
E agora com 4 argumentos:
Bem simples né?
Exemplo:
Exemplos do uso do script:
Com isso a gente resolve um problema e cria mais outros dois…
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:
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:
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:
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:
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:
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! :)
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.
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:
E tentar executar novamente:
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:
Agora é so chamar a função como…
Use a criatividade de um programador (afinal, programação é arte) e comece a aprimorar suas ferramentas bash! :)
Fonte: http://www.devin.com.br/shell-script-tratamento-de-argumentos-e-opcoes/
Continue reading →
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)
01
02
03
04
05
06
07
08
09
10
11
12
13
14
| #!/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 |
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! |
$ ./tmp.sh naosei testando Numero de argumentos: 2 Argumento 1: naosei Argumento 2: testando |
$ ./tmp.sh a b c d Numero de argumentos: 4 Argumento 1: a Argumento 2: b Argumento 3: c Argumento 4: d |
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:
01
02
03
04
05
06
07
08
09
10
11
| #!/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 |
$ ./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! |
- 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.
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”
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
| #!/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 |
Note que para cada opção que precisamos, colocamos uma letra no primeiro argumento do getopts:
1
| while getopts "hvo:umsf" OPTION |
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") |
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] |
1
| shift $((OPTIND-1)) |
./tmp.sh -u -o arquivo.log -m argumento1 argumento2 |
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:
01
02
03
04
05
06
07
08
09
10
11
12
13
| #!/bin/bash function Dummy() { echo "Numero de argumentos: $#" COUNT=0 for ARG in $*; do COUNT=` expr $COUNT + 1` echo "Argumento $COUNT: $ARG" done } Dummy |
$ ./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 |
1
| Dummy a b c d |
$ ./tmp.sh Numero de argumentos: 4 Argumento 1: a Argumento 2: b Argumento 3: c Argumento 4: d |
1
2
3
4
5
| function PrintUsage() { [ "$1" ] && echo - ne "Erro: $1\n" echo "Uso: $(basename $0) <-umsf> [-ohv]" exit 1 } |
PrintUsage "Faltando parâmetros." PrintUsage "Opção inválida." PrintUsage "No donut for you." |
Fonte: http://www.devin.com.br/shell-script-tratamento-de-argumentos-e-opcoes/