Escolar Documentos
Profissional Documentos
Cultura Documentos
PROFISSIONAL
Novatec
Quarta reimpresso
Terceira reimpresso
Segunda reimpresso
Primeira reimpresso
Primeira edio
08-01176
CDD-005.369
ndices para catlogo sistemtico:
1. Shell Script : Computadores : Programas :
Processamento de dados
005.369
(CIP)
Prefcio
19
20
possvel, confundindo em vez de ajudar. A pior de todas, com larga vantagem no nvel
de frustrao, era a temida man bash, com suas interminveis pginas que eu lia, relia,
trelia e no entendia nada. Ah, meu ingls era de iniciante, o que tornava o processo
ainda mais cruel.
A Internet no ajudava em quase nada, pois as fontes de informao eram escassas. S havia algumas poucas pginas em ingls, com raros exemplos. Fruns? Blogs?
Lista de discusso? Passo-a-passo-receita-de-bolo? Esquea. Era man page e ponto.
Mas com o tempo fui me acostumando com aquela linguagem seca e tcnica das
man pages e aos poucos os comandos comearam a me obedecer. Os odiosos command
not found e syntax error near unexpected token tornaram-se menos frequentes. Deixei
de perder arquivos importantes por ter digitado um comando errado, ou por ter
usado > ao invs de >>.
Dica: Leia man pages. chato, cansativo e confuso, mas compensa. Afinal, quem
aprende a dirigir em um jipe velho, dirige qualquer carro.
Quanto mais aprendia sobre os comandos e suas opes, mais conseguia automatizar tarefas rotineiras do servidor, fazendo pequenos scripts.
Cdigos simples, com poucos comandos, mas que poupavam tempo e garantiam
a padronizao na execuo. Ainda tenho alguns deles aqui no meu $HOME, vejamos:
mudar o endereo IP da mquina, remover usurio, instalao do MRTG, gerar arquivo de configurao do DHCPD.
Em alguns meses j eram dezenas de scripts para as mais diversas tarefas. Alguns
mais importantes que outros, alguns mais complexos: becape, gravao de CDs, gerao de pginas HTML, configurao de servios, conversores, wrappers e diversas
pequenas ferramentas para o controle de qualidade do Conectiva Linux. Que verstil
o shell!
Mas nem tudo era flores. Alguns scripts cresceram alm de seu objetivo inicial,
ficando maiores e mais complicados. Cada vez era mais difcil encontrar o lugar certo para fazer as alteraes, tomando o cuidado de no estragar seu funcionamento.
Outros tcnicos tambm participavam do processo de manuteno, adicionando
funcionalidades e corrigindo bugs, ento era comum olhar um trecho novo do cdigo que demorava um bom tempo at entender o que ele fazia e por que estava ali.
Era preciso amadurecer. Mais do que isso, era preciso fazer um trabalho mais
profissional.
21
Prefcio
Todo este processo fez-me evoluir como profissional e como programador. Primeiro,
aprendi a procurar por conhecimento em vez de cdigos prontos para copiar e colar.
Depois, aprendi o valor imenso de um cdigo limpo e informativo.
Ento, nasceu este livro de shell.
Ao olhar para o Sumrio, voc ver uma lista de tecnologias e tcnicas para tornar
seus scripts mais poderosos. Mas no quero que voc simplesmente aprenda a fazer
um CGI ou consiga entender expresses regulares. Quero que voc tambm evolua.
Quero que voc faa programas de verdade em vez de meros scripts toscos.
Prepare-se para uma imerso em shell. Ao ler cada captulo, voc far um mergulho
profundo no assunto, aprendendo bem os fundamentos para depois poder aplic-los
com a segurana de quem sabe o que est fazendo. Os cdigos no so entregues
prontos em uma bandeja. Passo a passo vamos juntos construindo os pedaos dos
programas, analisando seu funcionamento, detectando fraquezas e melhorando at
chegar a uma verso estvel. Voc no ficar perdido, pois avanaremos conforme os
conceitos so aprendidos.
Imagine-se lendo o manual de seu primeiro carro zero quilmetro, sentado
confortavelmente no banco do motorista, sentindo aquele cheirinho bom de carro
22
novo. Voc no tem pressa, pode ficar a noite toda saboreando aquelas pginas, testando todos os botes daquele painel reluzente. Se o manual diz que a luz acender
ao apertar o boto vermelho, o que voc faz imediatamente? Aperta o boto e sorri
quando a luz acende.
De maneira similar, estude este livro com muita calma e ateno aos detalhes.
No salte pargrafos, no leia quando estiver com pressa.
Reserve um tempo de qualidade para seus estudos. Com um computador ao alcance das mos, teste os conceitos durante a leitura. Digite os comandos, faa variaes,
experimente! Brinque na linha de comando, aprendendo de maneira prazerosa.
Vamos?
Visite o site do livro (www.shellscript.com.br) para baixar os cdigos-fonte de todos os
programas que estudaremos a seguir.
Captulo 4
Opes de linha de
comando (-f, --foo)
57
58
Formato
Exemplos
find
-<palavra>
-name,-type
ps
<letra>
a u w x
dd
<palavra>=
H tambm os aplicativos GNU, que de uma forma ou outra esto ligados FSF
(Free Software Foundation) e preferem a licena GPL. Estes so programas com
cdigo mais recente, que vieram para tentar substituir os aplicativos do Unix. Esto
presentes em todos os cantos de um sistema Linux, alguns exemplares habitam no
Mac e tambm podem ser instalados no Windows por intermdio do Cygwin. Eles
seguem um padro que no forado, porm recomendado e adotado pela maioria.
59
Exemplos
Descrio
-<letra>
-h, -V
--<palavra>
Opes estabelecidas
Opo curta
Opo longa
Descrio
-h
--help
-V
--version
-v
--verbose
-q
--quiet
--
60
Opes recomendadas
Opo curta
Opo longa
Descrio
Exemplo
-c
--chars
-d
--delimiter
-f
--file
-i
--ignore-case
-n
--number
-o
--output
-w
--word
grep -w, wc -w
usuarios.sh
#!/bin/bash
# usuarios.sh
#
Este um programa bem simples que mostra uma listagem dos usurios do
sistema, no formato login TAB nome completo. Seu cdigo resume-se a uma
nica linha com um cut que extrai os campos desejados do arquivo de usurios
(/etc/passwd) e um tr filtra esta sada transformando todos os dois-pontos em TABs.
Veja um exemplo de sua execuo:
61
System Administrator
uucp
Printing Services
mysql
MySQL Server
eppc
sshd
qtss
Realmente simples, no? Nas prximas pginas, esta pequena gema de uma linha
crescer para suportar opes e aumentar um pouco a sua gama de funcionalidades.
Mas, claro, sem perder o foco inicial: mostrar a lista de usurios. Nada de ler e-mail
ou trazer um Wiki embutido ;)
$1
$2
$3 $4
$5
62
Ento, se nosso programa foi chamado como usuarios.sh -h, a opo estar guardada
em $1. A ficou fcil. Basta conferir se o valor de $1 -h, em caso afirmativo, mostramos
a tela de ajuda e samos do programa. Traduzindo isso para shell fica:
usuarios.sh (v2)
#!/bin/bash
# usuarios.sh
#
MENSAGEM_USO="
Uso: $0 [-h]
-h
"
# Tratamento das opes de linha de comando
if test "$1" = "-h"
then
echo "$MENSAGEM_USO"
exit 0
fi
# Processamento
L nos cabealhos deixamos claro que esta a segunda verso do programa e que
ela traz de novidade a opo -h. A mensagem de uso guardada em uma varivel,
usando o $0 para obter o nome do programa. Isso bom porque podemos mudar
o nome do programa sem precisar nos preocupar em mudar a mensagem de ajuda
junto. Em seguida, um if testa o contedo de $1, se for o -h que queremos, mostra a
ajuda e sai com cdigo de retorno zero, que significa: tudo certo.
$ ./usuarios-2.sh -h
Uso: ./usuarios-2.sh [-h]
-h
63
$ ./usuarios-2.sh -X
root
System Administrator
uucp
Printing Services
mysql
MySQL Server
eppc
sshd
qtss
echo "$MENSAGEM_USO"
exit 0
# mostra a verso
...
fi
E a cada nova opo, o if vai crescer mais. Mmmm, espera. Em vez de fazer um if
monstruoso, cheio de braos, aqui bem melhor usar o case. De brinde ainda ganhamos a opo * para pegar as opes invlidas. Veja como fica melhor e mais legvel:
64
;;
-V)
;;
*)
;;
echo "$MENSAGEM_USO"
exit 0
# mostra a verso
# opo invlida
esac
Para a opo invlida fcil, basta mostrar uma mensagem na tela informando
ao usurio o erro e sair do programa com cdigo de retorno 1. Um echo e um exit
so suficientes. A verso basta mostrar uma nica linha com o nome do programa e
a sua verso atual, ento sai com retorno zero. Mais um echo e um exit. Parece fcil.
usuarios.sh (v3)
#!/bin/bash
# usuarios.sh
#
MENSAGEM_USO="
-V
"
65
;;
-V)
;;
*)
;;
echo "$MENSAGEM_USO"
exit 0
echo $0 Verso 3
exit 0
esac
# Processamento
Mais uma vez o cabealho foi atualizado para informar as mudanas. Isso deve se
tornar um hbito, uma regra que no pode ser quebrada. Acostume-se desde j. Em
seguida, a mensagem de uso agora mostra que o programa tambm possui a opo
-V. O pipe em [-h | -V] informa que voc pode usar a opo -h ou a opo -V, e ambas
so opcionais (indicado pelos colchetes). Depois vem o case com cada opo bem
alinhada, tornando a leitura agradvel. No -V mostrada a verso atual e a sada
normal. O asterisco vale para qualquer outra opo fora o -h e o -V, e alm de mostrar
a mensagem informando que a opo digitada invlida, sai com cdigo de erro (1).
$ ./usuarios-3.sh -h
Uso: ./usuarios-3.sh [-h | -V]
-h
-V
$ ./usuarios-3.sh -V
./usuarios-3.sh Verso 3
$ ./usuarios-3.sh -X
Opo invlida: -X
$ ./usuarios-3.sh
Opo invlida:
$
66
if test -n "$1"
then
fi
;;
J que estamos aqui, com o -h e o -V funcionando, que tal tambm adicionar suas
opes equivalentes --help e --version? Vai ser muito mais fcil do que voc imagina.
Lembre-se de que dentro do case possvel especificar mais de uma alternativa para
cada bloco? Ento, alterando somente duas linhas do programa ganhamos de brinde
mais duas opes.
case "$1" in
-h | --help)
...
;;
-V | --version)
...
;;
*)
...
;;
esac
67
Uma ltima alterao seria melhorar este esquema de mostrar a verso do programa. Aquele nmero ali fixo dentro do case tende a ser esquecido. Voc vai modificar o
programa, lanar outra verso e no vai se lembrar de aumentar o nmero da opo
-V. Por outro lado, o nmero da verso est sempre l no cabealho, no registro das
mudanas. Ser que...
$ grep '^# Verso ' usuarios-3.sh
# Verso 3
Ei, isso foi legal! Alm de extrair a verso do programa automaticamente, ainda
nos foramos a sempre registrar nos cabealhos o que mudou na verso nova, para
no quebrar o -V. Simples e eficiente. Vejamos como ficou esta verso nova do cdigo.
usuarios.sh (v4)
#!/bin/bash
# usuarios.sh
#
MENSAGEM_USO="
68
-V, --version
-h | --help)
;;
echo "$MENSAGEM_USO"
exit 0
-V | --version)
exit 0
;;
*)
if test -n "$1"
then
fi
;;
esac
# Processamento
Agora, sim, podemos considerar que o programa ficou estvel aps a adio de
quatro opes de linha de comando, alm do tratamento de opes desconhecidas.
Antes de continuar adicionando opes novas, bom conferir se est mesmo tudo
em ordem com o cdigo atual.
$ ./usuarios-4.sh -h
Uso: usuarios-4.sh [-h | -V]
-h, --help
-V, --version
69
$ ./usuarios-4.sh --help
Uso: usuarios-4.sh [-h | -V]
-h, --help
-V, --version
$ ./usuarios-4.sh -V
usuarios-4.sh Verso 4
$ ./usuarios-4.sh --version
usuarios-4.sh Verso 4
$ ./usuarios-4.sh --foo
Opo invlida: --foo
$ ./usuarios-4.sh -X
Opo invlida: -X
$ ./usuarios-4.sh
root
System Administrator
uucp
Printing Services
mysql
MySQL Server
eppc
sshd
qtss
70
Agora vamos adicionar algumas opes que possuem um comportamento diferente. Elas vo ter seu cantinho dentro do case, mas em vez de terminar a execuo
do programa, vo definir variveis e no final a lista de usurios tambm dever ser
mostrada. Isso vai requerer uma alterao estrutural em nosso programa. Mas vamos
com calma.
Primeiro, o mais importante avaliar: que tipo de opo seria til adicionar ao
nosso programa? Como programadores talentosos e criativos que somos, podemos
adicionar qualquer coisa ao cdigo, o cu o limite. Mas ser que uma enorme
quantidade de opes reflete qualidade? Adicionar toda e qualquer opo que vier
mente realmente benfico ao programa e aos usurios? Avalie o seguinte:
A opo --FOO vai trazer muita complexidade ao cdigo atual? Sua implementao ser muito custosa ao programador?
A opo --FOO auto-explicvel? Ou preciso um pargrafo inteiro para descrever o que ela faz? Se est difcil dar um nome, pode ser um sintoma que ela
nem deveria existir em primeiro lugar...
71
Para no ser apenas mais um personagem dessa histria que se repete diariamente,
faa um favor a si mesmo: leia a lista anterior toda vez que pensar em adicionar uma
opo nova ao seu programa. Pense, analise, avalie, questione. Se a opo passar por
todas estas barreiras e provar ser realmente til, implemente-a.
Cara chato, n? Mas se no tiver um chato para te ensinar as coisas chatas (porm
importantes), como voc vai evoluir como programador? A chatice de hoje a qualidade de
amanh em seu trabalho. Invista no seu potencial e colha os frutos no futuro!
lp
Printing Services
mysql
MySQL Server
qtss
sshd
System Administrator
Sabemos que existe o comando sort e que ele ordena as linhas. Mas o usurio no
obrigado a saber disso. Ele no mximo ler a nossa tela de ajuda e ali saber das
possibilidades de uso do programa. Ento, apesar de ter uma implementao trivial,
o usurio se beneficiar com esta opo. Nosso programa ter duas opes novas -s
e --sort que sero equivalentes e serviro para que a lista seja ordenada.
Sim, poderia ser -o e --ordena para que as opes ficassem em portugus. Mas como
j temos --help e --version em ingls, prefervel manter o padro do que misturar
os idiomas. Outra opo seria deixar tudo em portugus alterando as opes atuais para
ajuda e --versao (sem acentos para evitar problemas!). Avalie o perfil de seus usurios
e decida qual idioma utilizar.
72
Para adicionar esta opo nova temos que inclu-la na mensagem de ajuda, e
tambm dentro do case. Alguma varivel global ser necessria para indicar se a sada ser ou no ordenada, e esta opo mudar o valor desta varivel. Um esqueleto
deste esquema seria assim:
ordenar=0
...
# Tratamento das opes de linha de comando
case "$1" in
-s | --sort)
ordenar=1
;;
...
esac
...
if test "$ordenar" = 1
then
fi
# ordena a listagem
73
if test "$ordenar" = 1
then
else
fi
Mas isso traz vrios problemas. O primeiro a repetio de cdigo, o que nunca
benfico. Sero dois lugares para mudar caso alguma alterao precise ser feita na
dupla cut | tr. Esta soluo tambm no ir ajudar quando precisarmos adicionar
outras opes que tambm manipulem a listagem. O melhor fazer cada tarefa
isoladamente, para que a independncia entre elas garanta que todas funcionem
simultaneamente: primeiro extrai a lista e guarda em uma varivel. Depois ordena,
se necessrio.
# Extrai a listagem
fi
Assim o cdigo fica maior, porm muito mais flexvel e poderoso. A vantagem da
separao das tarefas ficar evidente quando adicionarmos mais opes ao programa.
J so muitas mudanas, hora de lanar uma verso nova:
usuarios.sh (v5)
#!/bin/bash
# usuarios.sh
#
74
ordenar=0
MENSAGEM_USO="
"
-s, --sort
-h, --help
-V, --version
-s | --sort)
ordenar=1
;;
-h | --help)
;;
echo "$MENSAGEM_USO"
exit 0
-V | --version)
;;
*)
if test -n "$1"
then
exit 1
fi
;;
esac
75
# Extrai a listagem
lista=$(cut -d : -f 1,5 /etc/passwd)
# Ordena a listagem (se necessrio)
if test "$ordenar" = 1
then
lista=$(echo "$lista" | sort)
fi
# Mostra o resultado para o usurio
echo "$lista" | tr : \\t
O cdigo est simples de entender, certo que a opo nova vai funcionar. Mas
no custa testar, so apenas alguns segundos investidos. E v que aparece algum bug
aliengena que nossos olhos terrqueos no consigam captar?
$ ./usuarios-5.sh --sort
amavisd Amavisd User
lp
Printing Services
mysql
MySQL Server
qtss
sshd
System Administrator
Ufa, no foi desta vez que os ETs tiraram o nosso sono... Agora que o cdigo do
programa est com uma boa estrutura, fica fcil adicionar duas opes novas: uma
para inverter a ordem da lista e outra para mostrar a sada em letras maisculas. Digamos --reverse e --uppercase. Como programadores experientes em shell, sabemos que o
tac inverte as linhas de um texto e que o tr pode converter um texto para maisculas.
Assim, o cdigo para suportar estas opes novas ser to trivial quanto o do --sort.
76
uucp
qtss
root
System Administrator
MySQL Server
lp
Printing Services
eppc
UUCP
QTSS
ROOT
SYSTEM ADMINISTRATOR
MYSQL SERVER
LP
PRINTING SERVICES
EPPC
Ah, como bom programar em shell e ter mo todas estas ferramentas j prontas
que fazem todo o trabalho sujo, no mesmo? Um nico detalhe que est faltando
no cdigo de nosso programa que ele sempre verifica o valor de $1, no estando
pronto para receber mltiplas opes. E agora ele precisar disso, pois o usurio pode
querer usar todas ao mesmo tempo:
usuarios.sh --sort --reverse --uppercase
77
$5
$4
$3
$2
$1
Caixa
SHIFT
$4
$3
$2
$1
Caixa
78
case "$1" in
-s | --sort)
ordenar=1
;;
...
esac
shift
done
Veja como ficou a verso nova do cdigo com este loop implementado, bem como
as opes novas --reverse e --uppercase. Perceba tambm que a tela de ajuda mudou
um pouco, usando o formato [OPES] para simplificar a sintaxe de uso, indicando que
todas as opes seguintes no so obrigatrias (colchetes). Outra mudana dentro do
case, foi a retirada do teste de existncia do parmetro $1, que era feito na opo padro
(asterisco). Ele no mais necessrio visto que o while j est fazendo esta verificao.
usuarios.sh (v6)
#!/bin/bash
# usuarios.sh
#
ordenar=0
inverter=0
maiusculas=0
OPES:
"
-r, --reverse
Inverte a listagem
-s, --sort
-u, --uppercase
-h, --help
-V, --version
case "$1" in
-s | --sort)
ordenar=1
;;
-r | --reverse)
inverter=1
;;
-u | --uppercase)
maiusculas=1
;;
-h | --help)
;;
echo "$MENSAGEM_USO"
exit 0
-V | --version)
;;
79
80
;;
esac
shift
done
# Extrai a listagem
fi
Antes de passar para a prxima opo a ser includa, cabe aqui uma otimizao
de cdigo que melhorar a sua legibilidade. Alteraremos dois trechos, sem incluir
nenhuma funcionalidade nova, apenas o cdigo ser reformatado para ficar mais
compacto e, ao mesmo tempo, mais legvel. Isso no acontece sempre, geralmente
compactar significa tornar ruim de ler. Mas como neste caso as linhas so praticamente
iguais, mudando apenas uma ou outra palavra, o alinhamento beneficia a leitura:
81
Cdigo compacto
case "$1" in
-s | --sort)
;;
ordenar=1
case "$1" in
-r | --reverse)
;;
-r | --reverse ) inverter=1
inverter=1
-u | --uppercase)
;;
maiusculas=1
-s | --sort
) ordenar=1
;;
;;
-u | --uppercase) maiusculas=1 ;;
...
esac
...
esac
fi
fi
test "$inverter"
fi
82
A ltima opo que adicionaremos ao nosso programa ser diferente. Ela se chamar --delimiter, e assim como no cut, esta opo indicar qual caractere ser usado
como delimitador. Em nosso contexto, isso se aplica ao separador entre o login e o
nome completo do usurio, que hoje est fixo no TAB. Veja a diferena na sada do
programa, com esta opo nova:
$ ./usuarios-7.sh | grep root
root
System Administrator
case "$1" in
-d | --delimiter)
shift
delim="$1"
;;
...
esac
shift
done
Primeiro feito um shift manual para que a opo -d (ou --delimiter) seja descartada, fazendo a fila andar e assim seu argumento fica sendo o $1, que ento salvo
em $delim. Simples, no? Sempre que tiver uma opo que tenha argumentos, use esta
tcnica. Ah, mas e se o usurio no passou nenhum argumento, como em usuarios.sh -d?
# Tratamento das opes de linha de comando
while test -n "$1"
do
case "$1" in
-d | --delimiter)
83
shift
delim="$1"
if test -z "$delim"
then
exit 1
fi
;;
...
esac
shift
done
Agora sim, a exceo foi tratada e o usurio informado sobre seu erro. Chega, n?
Quase 100 linhas est bom demais para um programa que inicialmente tinha apenas
10. Mas, em compensao, agora ele possui 12 opes novas (seis curtas e suas alternativas longas) e muita flexibilidade de modificao de sua execuo, alm de estar mais
amigvel com o usurio por ter uma tela de ajuda. Veja como ficou a ltima verso:
usuarios.sh (v7)
#!/bin/bash
# usuarios.sh
#
84
ordenar=0
maiusculas=0
inverter=0
delim='\t'
MENSAGEM_USO="
Inverte a listagem
-u, --uppercase
-s, --sort
-h, --help
"
-V, --version
case "$1" in
-s | --sort
) ordenar=1
-r | --reverse ) inverter=1
;;
;;
-u | --uppercase) maiusculas=1 ;;
-d | --delimiter)
shift
delim="$1"
if test -z "$delim"
then
fi
;;
85
-h | --help)
;;
echo "$MENSAGEM_USO"
exit 0
-V | --version)
;;
*)
;;
esac
shift
done
# Extrai a listagem
test "$inverter"
Ufa, como cresceu! Voc pode usar este programa como modelo para seus prprios
programas que tero opes de linha de comando, toda essa estrutura reaproveitvel.
Para fechar de vez com chave de ouro, agora faremos o teste final de funcionamento,
usando todas as opes, inclusive misturando-as. Espero que no aparea nenhum
bug :)
$ ./usuarios-7.sh --help
Uso: usuarios-7.sh [OPES]
86
Inverte a listagem
-u, --uppercase
-s, --sort
-h, --help
-V, --version
$ ./usuarios-7.sh -V
usuarios-7.sh Verso 7
$ ./usuarios-7.sh
root
System Administrator
uucp
Printing Services
mysql
MySQL Server
eppc
sshd
qtss
$ ./usuarios-7.sh --sort
amavisd Amavisd User
lp
Printing Services
mysql
MySQL Server
qtss
sshd
System Administrator
uucp
qtss
root
System Administrator
MySQL Server
lp
Printing Services
eppc
UUCP
QTSS
ROOT
SYSTEM ADMINISTRATOR
MYSQL SERVER
LP
PRINTING SERVICES
EPPC
$ ./usuarios-7.sh -s -d ,
amavisd,Amavisd User
daemon,System Services
eppc,Apple Events User
jabber,Jabber User
lp,Printing Services
mailman,Mailman user
mysql,MySQL Server
postfix,Postfix User
87
88
unknown,Unknown User
na mo
Opes curtas juntas ou separadas (-abc e -a -b -c) Opes curtas somente separadas (-a -b -c)
89
getopts-teste.sh
#!/bin/bash
# getopts-teste.sh
#
case $opcao in
esac
done
echo
90
Antes de entrarmos nos detalhes do cdigo, veja alguns exemplos de sua execuo,
que ajudaro a compreender o que o getopts faz. No primeiro exemplo foram passadas
duas opes (uma simples e outra com argumento) e um argumento solto, que um
nome de arquivo qualquer. No segundo exemplo temos apenas o nome de arquivo,
sem opes. Por fim, no terceiro fizemos tudo errado :)
$ ./getopts-teste.sh -a FOO -s /tmp/arquivo.txt
OK Opo com argumento (-a), recebeu: FOO
OK Opo simples (-s)
INDICE: 4
RESTO: /tmp/arquivo.txt
$ ./getopts-teste.sh /tmp/arquivo.txt
INDICE: 1
RESTO: /tmp/arquivo.txt
$ ./getopts-teste.sh -z -a
ERRO Opo invlida: z
Entendeu? Funcionar ele funciona, mas tem uma srie de detalhes que so importantes e devem ser respeitados. Estes so os passos necessrio para usar o getopts
corretamente:
O primeiro argumento para o getopts uma string que lista todas as opes
vlidas para o programa:
91
Dentro do case, liste todas as opes vlidas. Note que no necessrio o hfen!
Se a opo requer um argumento, ele estar guardado na varivel $OPTARG. Trate
tambm as duas alternativas especiais que o getopts usa em caso de erro:
Por fim, se processadas todas as opes e ainda sobrar algum argumento, ele
tambm pode ser obtido. Isso geralmente acontece quando o aplicativo aceita
receber um nome de arquivo como ltimo argumento, assim como o grep. A
varivel $OPTIND guarda o ndice com a posio deste argumento. Como podem
ser vrios argumentos restantes, o mais fcil usar um shift N para apagar todas
as opes, sobrando apenas os argumentos. Onde N = $OPTIND - 1.
92
Opo simples: -a
a:
Variveis de ambiente
$OPTERR
$OPTARG
$OPTIND
O usuarios.sh, que estudamos bastante, pode ser modificado para funcionar usando o getopts. A desvantagem que somente as opes curtas podem ser utilizadas.
O interessante aqui ver o diff das duas verses, para ficar bem fcil enxergar as
diferenas das duas tcnicas:
# usuarios.sh
#
93
ordenar=0
maiusculas=0
inverter=0
delim='\t'
MENSAGEM_USO="
Inverte a listagem
- -u, --uppercase
- -s, --sort
+ -d C
+ -r
Inverte a listagem
+ -s
+ -u
- -h, --help
- -V, --version
+ -h
+ -V
"
# Tratamento das opes de linha de comando
- case "$1" in
+ case "$opcao" in
- -s | --sort
) ordenar=1
;;
94
;;
- -u | --uppercase) maiusculas=1 ;;
-
- -d | --delimiter)
- shift
- delim="$1"
-
-
if test -z "$delim"
- then
-
- fi
s) ordenar=1
;;
r) inverter=1
;;
u) maiusculas=1 ;;
+
+ d)
+ delim="$OPTARG"
;;
- -h | --help)
+ h)
;;
echo "$MENSAGEM_USO"
exit 0
- -V | --version)
+ V)
;;
- *)
exit 1
+ \?)
+ ;;
+
95
+ :)
+
;;
esac
# Extrai a listagem
test "$inverter"
-s
-r
-u
-h
-V
Inverte a listagem
96
usuarios-7-getopts.sh Verso 7g
$ ./usuarios-7-getopts.sh -sru -d ,
MAILMAN,MAILMAN USER
LP,PRINTING SERVICES
JABBER,JABBER USER