114
Dono: Flávio Cunha

Apostila Shell Flavio

Embed Size (px)

Citation preview

Page 1: Apostila Shell Flavio

Dono: Flávio Cunha

Page 2: Apostila Shell Flavio

ÍndiceMensagem Inicial.................................................................................................................................................1

AULA 1 − Revisão do Básico .............................................................................................................................2Revisão do Básico....................................................................................................................................2Exercícios para Desenferrujar..................................................................................................................7

AULA 2 − Programas Não São Scripts ............................................................................................................10A Diferença de um Programa para um Script........................................................................................10Por Quê Fazer Programas em Shell......................................................................................................11Programar em Shell é diferente!............................................................................................................11Características de um Programa de Qualidade.....................................................................................12

Cabeçalho Inicial.............................................................................................................................12Como Escrever Código Limpo.........................................................................................................16Como Comentar um Programa........................................................................................................17

Hora de Reavaliar Seus Conceitos........................................................................................................20Uso Racional de Variáveis...............................................................................................................20Fazendo Funções do Jeito Certo.....................................................................................................20

AULA 3 − Explorando as Possibilidades do Shell .........................................................................................22Programação envolvendo Chaves (Flags).............................................................................................22

Chaves como Configuração pelo Usuário.......................................................................................22Chaves Internas...............................................................................................................................23Detalhes Sobre o Nome da Chave..................................................................................................24

Como Depurar Programas (Debug).......................................................................................................24Checagem de Sintaxe com a opção −n...........................................................................................25Debug usando o comando echo......................................................................................................25Debug com a opção −x (e −v).........................................................................................................26Debug de Trechos Específicos (Liga/Desliga).................................................................................27Execução Passo−a−Passo..............................................................................................................27Debug Personalizado......................................................................................................................28Debug Personalizado e Categorizado.............................................................................................29

Fazendo Programas −−com −−opções..................................................................................................30Os Formatos Utilizados...................................................................................................................30E o Shell?........................................................................................................................................31Exemplos Com Opções Curtas.......................................................................................................31Exemplo Com Opções Longas........................................................................................................33

Os Segredos do Programador Shell......................................................................................................33Dicas Finais sobre Manutenção e Versionamento.................................................................................34

Versionamento.................................................................................................................................34Histórico de Mudanças: ChangeLog e NEWS.................................................................................35Agradecimentos a Quem Merece....................................................................................................36

AULA 4 − A Caixa de Ferramentas ..................................................................................................................37As Ferramentas do Sistema...................................................................................................................37

Abrindo a Caixa de Ferramentas.....................................................................................................38Analisando Cada Ferramenta................................................................................................................38

cat....................................................................................................................................................38cut....................................................................................................................................................39date..................................................................................................................................................40diff....................................................................................................................................................41echo.................................................................................................................................................42find...................................................................................................................................................43fmt....................................................................................................................................................45grep, egrep e fgrep..........................................................................................................................45head.................................................................................................................................................46od.....................................................................................................................................................47paste................................................................................................................................................48printf.................................................................................................................................................49rev....................................................................................................................................................49sed...................................................................................................................................................50

i

Page 3: Apostila Shell Flavio

ÍndiceAULA 4 − A Caixa de Ferramentas

seq...................................................................................................................................................52sort...................................................................................................................................................52tac....................................................................................................................................................53tail....................................................................................................................................................54tee....................................................................................................................................................54tr.......................................................................................................................................................55uniq..................................................................................................................................................56wc....................................................................................................................................................56xargs................................................................................................................................................57

Os Caracteres de Controle.....................................................................................................................58O Que São Caracteres de Controle.................................................................................................58Mostrando Cores na Tela................................................................................................................59Posicionando o Cursor....................................................................................................................59Comandos de Som..........................................................................................................................61Outros Comandos............................................................................................................................61Exemplos.........................................................................................................................................62

AULA 5 − Quem tem Medo de Expressões Regulares? ................................................................................65Expressões Regulares...........................................................................................................................65

O que são Expressões Regulares...................................................................................................65Os Metacaracteres..........................................................................................................................65Conhecendo Cada um dos Metacaracteres....................................................................................66Detalhes, detalhes, detalhes...........................................................................................................68

Parsing de Código HTML, XML e Semelhantes.....................................................................................69Extraindo Dados Automaticamente da Internet......................................................................................73

AULA 6 − Utilizando Arquivos de Configuração ............................................................................................74Explicação do Conceito..........................................................................................................................74Definindo um Formato............................................................................................................................74

Formatos de Arquivos Existentes....................................................................................................74Análise dos Formatos Apresentados...............................................................................................77Escolhendo um Formato..................................................................................................................78

O Parser.................................................................................................................................................79Codificação Acompanhada de um Parser.......................................................................................79Evolução para um Parser Genérico.................................................................................................80O Parser do Tipo Conversor............................................................................................................80

AULA 7 − Banco de Dados com Arquivos Texto............................................................................................82Explicação do Conceito..........................................................................................................................82

Onde Utilizar Bancos Textuais........................................................................................................82Diferenças Estruturais dos Tipos de Banco.....................................................................................83Formato Interno do Arquivo Texto...................................................................................................84

O Gerenciador do Banco........................................................................................................................86Agora o Shell Entra na Conversa....................................................................................................87Programação do Gerenciador.........................................................................................................87

Lista de Tarefas......................................................................................................................................87

AULA 8 − Interfaces Amigáveis com o Dialog................................................................................................89Apresentação.........................................................................................................................................89

O Que é o Dialog.............................................................................................................................89Os Tipos de Caixa...........................................................................................................................90As Principais Opções de Linha de Comando..................................................................................91

Como o Dialog Funciona........................................................................................................................91Entendendo os Parâmetros Obrigatórios da Linha de Comando....................................................91Como Reconhecer Respostas SIM ou NÃO....................................................................................92Como Obter a Resposta do Usuário................................................................................................93O Botão CANCELAR e a Tecla Esc................................................................................................94

Análise dos Tipos de Navegação de Telas............................................................................................95Menu Amarrado (em Loop)..............................................................................................................95

ii

Page 4: Apostila Shell Flavio

ÍndiceAULA 8 − Interfaces Amigáveis com o Dialog

Telas Encadeadas (Navegação Sem Volta)....................................................................................96Navegação Completa (Ida e Volta)..................................................................................................97

EXTRAS.................................................................................................................................................99Configurando as Cores das Caixas.................................................................................................99Fazendo Interfaces Realmente Gráficas.......................................................................................100

AULA 9 − CGI em Shell...................................................................................................................................101O Que é CGI........................................................................................................................................101O Primeiro CGI.....................................................................................................................................101

Variáveis Especiais do Ambiente CGI...........................................................................................103Utilizando Formulários..........................................................................................................................103

Primeiro Passo − Montar o Formulário..........................................................................................103Segundo Passo − Enviar e Analisar o Formulário.........................................................................105Terceiro Passo − Montar o CGI.....................................................................................................105

Depurando CGIs..................................................................................................................................106Onde Estão as Mensagens de Erro?.............................................................................................106Testando CGIs na Linha de Comando..........................................................................................107

AULA 10 − Apresentação dos Programas dos Alunos ................................................................................108Programa do Aluno..............................................................................................................................108

Mensagem Final ..............................................................................................................................................109

Direitos Autorais e Permissão de Cópia.......................................................................................................110

iii

Page 5: Apostila Shell Flavio

Mensagem InicialCaro aluno(a),

Esta apostila será nosso objeto de estudo nos próximos dias.

Ela foi feita especialmente para este curso, para juntar em um só documento, informaçõessobre diversas áreas da programação em Shell.

Ela detalha os conceitos e demonstra exemplos, mas a melhor parte quem vai fazer é você:programar. Durante todo o curso, a leitura será acompanhada de exercícios e análisespráticas. E nas aulas "temáticas", sempre terá um programa completo para fazer, com oacompanhamento do professor.

Espero que os temas abordados sejam úteis na sua vida pós−curso, e que a paixão pelaprogramação seja despertada (ou avivada) em seu coração.

Grande Abraço,

Aurélio Marinho Jargas

1 Dono: Flávio Cunha

Page 6: Apostila Shell Flavio

AULA 1 − Revisão do Básico

Revisão do Básico

O básico é o básico e este curso não é sobre Shell básico.

A seguir serão listadas várias informações num formato que facilita a consulta rápida. A idéia é que o começoda apostila seja o lugar para procurar os detalhes da sintaxe e opções mais usadas do Shell.

Aqui estão misturadas funcionalidades de vários Shells, então algumas podem não funcionar dependendo dequal o seu Shell ou a versão dele.

A revisão mesmo será os exercícios que estão logo após a listagem.

If, For, While, Case

if CONDIÇÃO for VAR in LISTA while CONDIÇÃO case $VAR in then do do txt1) comandos ;; comandos comandos comandos txt2) comandos ;; else done done txtN) comandos ;; comandos *) comandos ;; fi esac

Operadores do Shell

Operadores Aritméticos Operadores Relacionais

+ Adição == Igual

− Subtração != Diferente

* Multiplicação > Maior

/ Divisão >= Maior ou Igual

% Módulo < Menor

** Exponenciação <= Menor ou Igual

Operadores de Atribuição Operadores de BIT

= Atribui valor a uma variável << Deslocamento à esquerda

+= Incrementa a variável por uma constante >> Deslocamento à direita

−= Decrementa a variável por uma constante & E de bit (AND)

*= Multiplica a variável por uma constante | OU de bit (OR)

/= Divide a variável por uma constante ^ OU exclusivo de bit (XOR)

%= Resto da divisão por uma constante ~ Negação de bit

++ Incrementa em 1 o valor da variável ! NÃO de bit (NOT)

−− Decrementa em 1 o valor da variável

Operadores Lógicos Operadores de BIT (atribuição)

&& E lógico (AND) <<= Deslocamento à esquerda

|| OU lógico (OR) >>= Deslocamento à direita

&= E de bit

|= OU de bit

^= OU exclusivo de bit

2 Dono: Flávio Cunha

Page 7: Apostila Shell Flavio

Redirecionamento

Operador Ação

< Redireciona a entrada padrão (STDIN)

> Redireciona a saída padrão (STDOUT)

2> Redireciona a saída de erro (STDERR)

>> Redireciona a saída padrão, anexando

2>> Redireciona a saída de erro, anexando

| Conecta a saída padrão com a entrada padrão de outro comando

2>&1 Conecta a saída de erro na saída padrão

>&2 Conecta a saída padrão na saída de erro

>&− Fecha a saída padrão

2>&− Fecha a saída de erro

<<FIM Alimenta a entrada padrão (Here Document)

<<−FIM Alimenta a entrada padrão, cortando TABs

Comando test ou '['

Testes em variáveis Testes em arquivos

−lt Núm. é menor que (LessThan) −d é um diretório

−gt Núm. é maior que (GreaterThan) −e o arquivo existe

−le Núm. é menor igual (LessEqual) −f é um arquivo normal

−ge Núm. é maior igual (GreaterEqual) −G o grupo do arquivo é o do usuário atual

−eq Núm. é igual (EQual) −L o arquivo é um link simbólico

−ne Núm. é diferente (NotEqual) −O o dono do arquivo é o usuário atual

= String é igual −p o arquivo é um named pipe

!= String é diferente −r é arquivo tem permissão de leitura

−n String é não nula −s o tamanho do arquivo é maior que zero

−z String é nula −S o arquivo é um socket

! NÃO lógico (NOT) −w o arquivo tem permissão de escrita

−a E lógico (AND) −x é arquivo tem permissão de execução

−o OU lógico (OR) −nt o arquivo é mais recente (NewerThan)

−ot o arquivo é mais antigo (OlderThan)

−ef o arquivo é o mesmo (EqualFile)

Variáveis Especiais

$0 Parâmetro número 0 (nome do comando ou função)

$1 Parâmetro número 1 (da linha de comando ou função)

... Parâmetro número N ...

$9 Parâmetro número 9 (da linha de comando ou função)

AULA 1 − Revisão do Básico

3 Dono: Flávio Cunha

Page 8: Apostila Shell Flavio

${10} Parâmetro número 10 (da linha de comando ou função)

... Parâmetro número NN ...

$# Número total de parâmetros da linha de comando ou função

$* Todos os parâmetros, como uma string única

$@ Todos os parâmetros, como várias strings protegidas

$$ Número PID do processo atual (do próprio script)

$! Número PID do último job em segundo plano

$_ Último argumento do último comando executado

$? Código de retorno do último comando executado

Expansão de Variáveis

${var:−texto} Se var não está definida, retorna 'texto'

${var:=texto} Se var não está definida, defina−a com 'texto'

${var:?texto} Se var não está definida, retorna o erro 'texto'

${var:+texto} Se var está definida, retorna 'texto', senão retorna o vazio

${var} É o mesmo que $var, porém não ambíguo

${#var} Retorna o tamanho da string

${!var} Executa o conteúdo de $var (igual 'eval \$$var')

${!texto*} Retorna os nomes de variáveis começadas por 'texto'

${var:N} Retorna o texto à partir da posição 'N'

${var:N:tam} Retorna 'tam' caracteres à partir da posição 'N'

${var#texto} Corta 'texto' do início da string

${var##texto} Corta 'texto' do início da string (* guloso)

${var%texto} Corta 'texto' do final da string

${var%%texto} Corta 'texto' do final da string (* guloso)

${var/texto/novo} Substitui 'texto' por 'novo', uma vez

${var//texto/novo} Substitui 'texto' por 'novo', sempre

${var/#texto/novo} Se a string começar com 'texto', substitui 'texto' por 'novo'

${var/%texto/novo} Se a string terminar com 'texto', substitui 'texto' por 'novo'

Blocos e Agrupamentos

Sintaxe Descrição Exemplo

"..." Protege uma string, mas reconhece $, \ e ` como especiais "abc"

'...' Protege uma string (nenhum caractere é especial) 'abc'

$'...' Protege uma string, mas interpreta \n, \t, \a, ... 'abc\n'

` ... ` Executa comandos numa subshell, retornando o resultado `ls`

$(...) Executa comandos numa subshell, retornando o resultado $( ls )

(...) Executa comandos numa subshell ( ls )

AULA 1 − Revisão do Básico

4 Dono: Flávio Cunha

Page 9: Apostila Shell Flavio

((...)) Testa uma operação aritmética, retornando 0 ou 1 ((5 > 3))

$((...)) Retorna o resultado de uma operação aritmética $((5+3))

{...} Agrupa comandos em um bloco { ls ; }

[...] Testa uma expressão, retornando 0 ou 1 (alias para 'test') [ 5 −gt 3 ]

[[...]] Testa uma expressão, retornando 0 ou 1 (permite && e ||) [[ 5 > 3 ]]

Curingas para Nomes de Arquivo (glob)

Curinga Casa com... Exemplo

* Qualquer coisa *.txt

? Um caractere qualquer arquivo−??.zip

[...] Qualquer um dos caracteres listados [Aa]rquivo.txt

[^...] Qualquer um caractere, exceto os listados [^A−Z]*.txt

{...} Qualquer um dos textos separados por vírgula arquivo.{txt,html}

Curingas para os Itens do Comando Case

Curinga Casa com... Exemplo

* Qualquer coisa *.txt) echo ;;

? Um caractere qualquer arquivo−??.zip) echo ;;

[...] Qualquer um dos caracteres listados [0−9]) echo ;;

[^...] Qualquer um caractere, exceto os listados [^0−9]) echo ;;

...|... Qualquer um dos textos separados por | txt|html) echo ;;

Códigos de Retorno de Comandos

Código Significado Exemplo

0 Nenhum erro, execução terminou OK echo

1 A maioria dos erros comuns na execução echo $((1/0))

2 Erro de uso em algum 'builtin' do Shell −

126 Comando não executável (sem permissão) touch a ; ./a

127 Comando não encontrado ("command not found") echooo

128 O parâmetro para o 'exit' não é um decimal exit 1.0

128+n 128 + código do sinal que o matou kill −9 $PPID #exit 137

130 O programa interrompido com o Ctrl+C (128 + 2) −

255* Parâmetro para o 'exit' não está entre 0 e 255 exit −1

AULA 1 − Revisão do Básico

5 Dono: Flávio Cunha

Page 10: Apostila Shell Flavio

Caracteres ASCII Imprimíveis

32 64 @ 96 ` 162 ¢ 194 Â 226 â 33 ! 65 A 97 a 163 £ 195 Ã 227 ã 34 " 66 B 98 b 164 ¤ 196 Ä 228 ä 35 # 67 C 99 c 165 ¥ 197 Å 229 å 36 $ 68 D 100 d 166 ¦ 198 Æ 230 æ 37 % 69 E 101 e 167 § 199 Ç 231 ç 38 & 70 F 102 f 168 ¨ 200 È 232 è 39 ' 71 G 103 g 169 © 201 É 233 é 40 ( 72 H 104 h 170 ª 202 Ê 234 ê 41 ) 73 I 105 i 171 « 203 Ë 235 ë 42 * 74 J 106 j 172 ¬ 204 Ì 236 ì 43 + 75 K 107 k 173 − 205 Í 237 í 44 , 76 L 108 l 174 ® 206 Î 238 î 45 − 77 M 109 m 175 ¯ 207 Ï 239 ï 46 . 78 N 110 n 176 ° 208 Ð 240 ð 47 / 79 O 111 o 177 ± 209 Ñ 241 ñ 48 0 80 P 112 p 178 ² 210 Ò 242 ò 49 1 81 Q 113 q 179 ³ 211 Ó 243 ó 50 2 82 R 114 r 180 ´ 212 Ô 244 ô 51 3 83 S 115 s 181 µ 213 Õ 245 õ 52 4 84 T 116 t 182 ¶ 214 Ö 246 ö 53 5 85 U 117 u 183 o 215 × 247 ÷ 54 6 86 V 118 v 184 ¸ 216 Ø 248 ø 55 7 87 W 119 w 185 ¹ 217 Ù 249 ù 56 8 88 X 120 x 186 º 218 Ú 250 ú 57 9 89 Y 121 y 187 » 219 Û 251 û 58 : 90 Z 122 z 188 ¼ 220 Ü 252 ü 59 ; 91 [ 123 { 189 ½ 221 Ý 253 ý 60 < 92 \ 124 | 190 ¾ 222 Þ 254 þ 61 = 93 ] 125 } 191 ¿ 223 ß 255 ÿ 62 > 94 ^ 126 ~ 192 À 224 à 63 ? 95 _ 161 ¡ 193 Á 225 á

Códigos Prontos

Condicionais com o IF

if [ −f "$arquivo" ]; then echo 'Arquivo encontrado'; fi if [ ! −d "$dir" ]; then echo 'Diretório não encontrado'; fi if [ $i −gt 5 ]; then echo 'Maior que 5'; else echo 'Menor que 5'; fi if [ $i −ge 5 −a $i −le 10 ]; then echo 'Entre 5 e 10, incluindo'; fi if [ "$user" = 'root' ]; then echo 'Oi root'; fi if grep −qs 'root' /etc/passwd; then echo 'Usuário encontrado'; fi

Condicionais com o E (&&) e OU (||)

[ −f "$arquivo" ] && echo 'Arquivo encontrado' [ −d "$dir" ] || echo 'Diretório não encontrado' grep −qs 'root' /etc/passwd && echo 'Usuário encontrado' cd "$dir" && rm "$arquivo" && touch "$arquivo" && echo 'feito!' [ "$1" ] && param=$1 || param='valor padrão' [ "$1" ] && param=${1:−valor padrão} [ "$1" ] || { echo "Uso: $0 parâmetro" ; exit 1 ; }

Adicionar 1 à variável $i

i=`expr $i + 1` i=$((i+1)) let i=i+1 let i+=1 let i++

Loop de 1 à 10

for i in 1 2 3 4 5 6 7 8 9 10; do echo $i; done for i in $(seq 10); do echo $i; done for ((i=1;i<=10;i++)); do echo $i; done i=1 ; while [ $i −le 10 ]; do echo $i ; i=$((i+1)) ; done i=1 ; until [ $i −gt 10 ]; do echo $i ; i=$((i+1)) ; done

AULA 1 − Revisão do Básico

6 Dono: Flávio Cunha

Page 11: Apostila Shell Flavio

Loop nas linhas de um arquivo ou saída de comando

cat /etc/passwd | while read LINHA; do echo "$LINHA"; done grep 'root' /etc/passwd | while read LINHA; do echo "$LINHA"; done while read LINHA; do echo "$LINHA"; done < /etc/passwd while read LINHA; do echo "$LINHA"; done <(grep 'root' /etc/passwd)

Exercícios para Desenferrujar

Seguem 10 exercícios de dificuldade crescente, para relembrar o básico de Shell. Todos são relativamentepequenos, podendo ser feitos com poucas linhas.

Mas não desanime caso não consiga fazer alguns, pois apesar de pequenos eles requerem conhecimento devários aspectos do Shell.

Exercício 1 − zerador.shRecebe um número como parâmetro e o diminui até chegar a zero, mostrando na tela cada passo,numa mesma linha. Exemplo:

$ ./zerador.sh 5 5 4 3 2 1 0

$ ./zerador.sh 10 10 9 8 7 6 5 4 3 2 1 0

Exercício 2 − relacao.shRecebe dois números como parâmetro e mostra a relação entre eles. Exemplo:

$ ./relacao.sh 3 5 3 é menor 5

$ ./relacao.sh 5 3 5 é maior 3

$ ./relacao.sh 5 5 5 é igual 5

Exercício 3 − parametros.shMostra na tela todos os parâmetros recebidos na linha de comando, contando−os. Exemplo:

$ ./parametros.sh a b c d e f Parâmetro 1: a Parâmetro 2: b Parâmetro 3: c Parâmetro 4: d Parâmetro 5: e Parâmetro 6: f

Exercício 4 − juntatudo.shMostra na tela "grudados" todos os parâmetros recebidos na linha de comando, como uma únicapalavra. Exemplo:

$ ./juntatudo.sh a b c d e f verde azul abcdefverdeazul

Exercício 5 − eh_numero.shIdentifica se o parâmetro recebido na linha de comando é um número inteiro ou não. Exemplo:

$ ./eh_numero.sh 333 É número

$ ./eh_numero.sh 333a Não é número

$ ./eh_numero.sh % Não é número

$ ./eh_numero.sh −5

AULA 1 − Revisão do Básico

7 Dono: Flávio Cunha

Page 12: Apostila Shell Flavio

É número

Exercício 6 − shells.shDo arquivo /etc/passwd, mostra todos os shells (último campo) que os usuários usam. Não mostrarlinhas repetidas. Exemplo:

$ ./shells.sh /bin/bash /bin/false /bin/sync /sbin/halt /sbin/shutdown

Exercício 7 − users.shDo arquivo /etc/passwd, mostra o usuário e o nome completo de cada usuário do sistema (campos 1 e5) separados por um TAB.

Opcional: Não mostrar quando o nome completo é igual ao usuário, como em"root:x:0:0:root:/root:/bin/bash"

Exemplo:

$ ./users.sh ftp FTP User nobody Nobody named Domain name server xfs X Font Server mysql MySQL server aurelio Aurelio Marinho Jargas

Exercício 8 − sysusers.shDo arquivo /etc/passwd, mostra uma listagem com o usuário e o UID, separados por um TAB. Excluirda listagem usuários cujo UID seja maior do que 99. Exemplo:

$ ./sysusers.sh root 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6 halt 7 mail 8 news 9 uucp 10 operator 11 games 12 gopher 13 ftp 14 named 15 xfs 16

Exercício 9 − dirs.shRecebe uma rota de diretórios (relativa ou absoluta) e mostra cada parte do caminho em uma linha,contando quantos diretórios foram encontrados. Exemplo:

$ ./dirs.sh a/b/c/d/e/f dir1: a dir2: b dir3: c dir4: d dir5: e dir6: f

$ ./dirs.sh /etc/rc.d/init.d/ dir1: / dir2: etc dir3: rc.d dir4: init.d

AULA 1 − Revisão do Básico

8 Dono: Flávio Cunha

Page 13: Apostila Shell Flavio

Exercício 10 − substring.shRecebe duas strings como parâmetro e checa se uma das strings está contida dentro da outra. Sómostra mensagem informativa em caso de sucesso, do contrário não mostra nada. Exemplo:

$ ./substring.sh ana banana banana tem ana

$ ./substring.sh banana ana banana tem ana

$ ./substring.sh banana maria

$ ./substring.sh banana

$ ./substring.sh

$

AULA 1 − Revisão do Básico

9 Dono: Flávio Cunha

Page 14: Apostila Shell Flavio

AULA 2 − Programas Não São Scripts

A Diferença de um Programa para um Script

Em geral, qualquer programa feito em Shell é chamado de Script. Não importa seu tamanho, sua qualidade,sua função, é sempre chamado de Script. O que faremos neste curso, não serão Scripts, mas Programas.Vamos ver a diferença.

O que é um Script?

A palavra Script também é usada em português para referenciar o roteiro de uma peça de teatro ou produçãotelevisiva. Esse script é o caminho que os atores devem seguir, a descrição de todo o "show" do início até ofim.

Em programação Shell, um Script não é muito diferente disso. Ele é uma lista de comandos para seremexecutados em seqüência (um após o outro). Um roteiro pré−definido de comandos e parâmetros.

Geralmente o que está no Script é aquilo que o usuário digitaria no prompt. E de fato, apenas colocando todoo histórico da linha de comando num arquivo, se tem um Script!

A impressão que se dá, é que as pessoas não levam o "script" muito a sério. Fazem códigos feios, semcomentários, sem alinhamento, sem muita clareza. Parece que Scripts são sempre feitos "nas coxas" e porquem não tem muita noção de programação.

Mas e não é que esse é um grande trunfo da programação em Shell? Qualquer um pode fazer Scripts! Bastasaber usar a linha de comando e pronto, nasceu mais um "scripteiro". Por isso o Shell é tão difundido, épopular.

Como o Shell é poderoso e gostoso de usar, com o tempo mais e mais tarefas começam a serdesempenhadas por Scripts e estes começam a crescer, ficar lentos, complicados, difíceis de manter. Aquela"brincadeira" de programar de maneira desleixada, agora se tornou uma maçaroca sem início ou fim.

É normal também escrever Scripts rápidos, de poucas linhas, que é usado por alguns dias e depoissimplesmente esquecido. Como é fácil "perder" Scripts! Eles são descartáveis.

Mas tudo bem, isso não é um problema desde que se tenha em mente que o Script recém escrito não era paraser "sério". O problema é quando um Script desses é o responsável por uma tarefa importante, vital para ofuncionamento de uma empresa por exemplo.

Scripts são ótimos para automatizar tarefas repetitivas, e o lugar mais propício delas acontecerem é noservidor de arquivos e da rede. Os Administradores de Sistema sempre acabam recorrendo aos Scripts paranão precisarem fazer manualmente aquelas tarefas chatas, rotineiras.

Só que administradores em geral não são programadores, e o Shell passa a falsa ilusão que "programar éfácil", então o resultado é um emaranhado de pequeninos Scripts de "5 minutos" que mantêm serviçosimportantes funcionando, monitoram conexões, fazem becape... Já imaginou que seus e−mails importantespodem estar passando por um Script desses?

O que é um Programa?

Um Programa é um Script feito do jeito certo.

Um Programa não é uma maçaroca, não é enigmático e tampouco descartável. Um Programa é feito para serfuncional, eficiente e principalmente: é feito para ser atualizado.

Um programador não é um scripteiro. Ele reconhece a importância de um código limpo e legível, que facilite otrabalho de manutenção e compreensão de seu funcionamento.

De quê adianta fazer um código complicadíssimo, rápido e inovador, se na hora de atualizá−lo ninguémsouber como alterá−lo e não restar outra solução senão o famoso: "reescrever do zero"?

10 Dono: Flávio Cunha

Page 15: Apostila Shell Flavio

Programas não são feitos nas coxas. Eles são pensados, analisados, codificados com cautela, têmcomentários, cabeçalho, tratam erros e exceções, são alinhados, bonitos de se ver.

Um programa não é uma obra de arte imutável. Pelo contrário! Um Programa é vivo, mutante, imperfeito,incompleto, que está sempre melhorando, ficando menor/maior, mais rápido/lento. É raro encontrar programas"versão final", que não há mais o que melhorar.

Além da simples automatização de tarefas, programas são feitos para resolver problemas e suprirnecessidades. Problemas mudam, necessidades mudam, então Programas mudam!

Principais Diferenças entre Scripts e Programas

Script Programa

Codificação descuidada Codificação cautelosa

Código rápido e sem estrutura Código limpo

Pouca manutenção, descartável Vivo, evolução constante

Feito por um programador Feito por um ou mais programadores

Bugs são ignorados Bugs são encontrados e corrigidos

Por Quê Fazer Programas em Shell

O primeiro passo de quem aprende Shell é fazer Scripts. Administradores de Sistemas precisam fazer Scriptspara automatizar tarefas do servidor, usuários fazem Scripts para aprender a programar ou para criarpequenas ferramentas de auxílio.

É incrível como a cada dia mais e mais pessoas estão aprendendo Shell. Fazer Scripts é fácil e tranqüilo, compoucas linhas é possível desfrutar das vantagens que a automatização e padronização nos trazem.

Já Programas são um passo maior. É preciso de tempo de dedicação e estudo, para resolver problemas ecodificar soluções. Mas se existem várias linguagens de programação mais poderosas e flexíveis que o Shell,então por quê usá−lo para fazer Programas?

O ponto chave da resposta é o conhecimento prévio em Shell Script. Se a pessoa investiu seu tempo emaprender os comandos e estruturas do Shell, já sabe fazer seus Scripts e se sente à vontade com alinguagem, por que não dar um passo maior e fazer Programas completos?

A programação profissional em Shell é algo que não é muito custoso, pois não se sai do zero, e sim seaperfeiçoa um conhecimento que a pessoa já possui. Com isso o caminho a percorrer é menor e em poucotempo o antigo "scripteiro" poderá estar fazendo Programas com P maiúsculo.

E para aqueles que não entendem muito de Shell, mas já programam em outras linguagens, o caminhotambém é curto pois resta apenas aprender os detalhes de sintaxe e características do Shell, que sãoamigáveis por ser aprendidos no próprio prompt do sistema operacional.

De um jeito ou de outro, Programação Profissional em Shell é algo rápido de assimilar e gostoso deprogramar!

Programar em Shell é diferente!

Para quem conhece linguagens de programação tradicionais como C, Pascal e Cobol, ou as mais badaladasatualmente como Java, Perl, PHP e Python, logo notará que programar em Shell é diferente.

A programação é mais tranqüila, de alto nível. Não é preciso se preocupar com tipagem de variáveis, acesso ahardware, controle de memória, ponteiros, compilação, plataforma, módulos, bibliotecas, bits, bytes, little/bigendian, ...

AULA 2 − Programas Não São Scripts

11 Dono: Flávio Cunha

Page 16: Apostila Shell Flavio

Para o programador, resta a parte boa: ALGORITMOS. Ele fica livre para criar soluções e deixa de sepreocupar com limitações da máquina ou da linguagem.

Programar em Shell geralmente envolve a manipulação de texto, processos, cálculos e gerenciamento dearquivos. As tarefas complexas ficam para as ferramentas do sistema como grep, sed, dd e find que seencarregam dos bits e bytes e possuem interface amigável via opções de linha de comando.

Mas além de fácil, o Shell também é poderoso. Além de possuir as funcionalidades básicas de uma linguagemestruturada normal, e a integração "natural" com o Sistema Operacional e suas ferramentas, há as facilidadesde redirecionamento, em que é possível combinar vários programas entre si, multiplicando seus poderes eevitando reescrita de código.

Pelo uso intensivo dessas ferramentas e da possibilidade de interoperabilidade entre elas, a programação emShell é chamada do tipo LEGO, onde a maioria das peças necessárias já existe, bastando saber comocombiná−las para produzir soluções.

É a filosofia UNIX mesclando−se com a arte da programação.

Características de um Programa de Qualidade

Por estar sempre evoluindo e precisar de manutenção constante, um Programa tem um estilo de codificaçãodiferente de um Script. Um ou mais programadores podem estar envolvidos na manutenção de um mesmoPrograma, então quanto mais limpo e bem escrito o código, mais fácil será o trabalho de mantê−lofuncionando.

Como regra geral, o programador deve ter em mente que o código que ele está escrevendo pode precisarmudar dali alguns dias ou meses, e ele não vai mais ter todo o esquema de funcionamento em sua cabeça.Ou ainda, pode ser que outro programador precise alterá−lo, então quanto mais fácil e informativo o código,menos dores de cabeça e ligações desesperadas durante a madrugada ele gerará &:)

Existem várias maneiras de se deixar o código de um Programa mais "fácil e informativo". Algumas delas:

Cabeçalho inicial com detalhes sobre o funcionamento• Código alinhado (indent) e bem espaçado verticalmente• Comentários explicativos e esclarecedores• Nomes descritivos de Funções e Variáveis• Controle de alterações e Versões• Estrutura interna coesa e padronizada•

Entre outras que veremos adiante. Além disso, um Programa ainda pode ter "extras" para torná−lo maisprofissional:

Manual de Uso• Manual Técnico• Suíte de testes• Changelog detalhado• Base de Problemas conhecidos• Versões "Beta"• Arquivos de exemplo de comportamento (se aplicável)•

Veremos agora em detalhes os componentes de um Programa de qualidade, "o quê" ele deve ter para servisto como um trabalho profissional.

Cabeçalho Inicial

O cabeçalho inicial é a primeira parte do Programa, o primeiro texto que qualquer um que for ler seu códigofonte irá encontrar. Pelo seu posicionamento, é aconselhável colocar neste cabeçalho todas as informaçõesnecessárias para que o leitor tenha uma visão geral do Programa.

O cabeçalho é composto por várias linhas de comentário. Um comentário nada mais é do que uma frasenormal em português (ou inglês, dependendo do caso), precedida de um caractere '#'.

AULA 2 − Programas Não São Scripts

12 Dono: Flávio Cunha

Page 17: Apostila Shell Flavio

# Isto é um comentário echo Este é um comando

Pergunta Aleatória: Qual o nome do '#'? Algumas respostas: gradinha, cerquilha, sustenido, hash, jogo davelha...

Ao escrever um cabeçalho, imagine que informações um programador precisaria ter para poder entender doque se trata o programa, o que ele faz e como ele faz. Além disso, também são importantes informações comoo nome do autor e as data de criação e última modificação.

Como regra geral, este é formato de um cabeçalho informativo:

Rota do interpretador• Nome do programa• Descrição breve do propósito• Homepage do programa (se aplicável)• Nome do Autor• E−mail do Autor• Nome e E−mail do mantenedor (caso diferente do autor)• Descrição detalhada do funcionamento• Data de criação• Histórico de mudanças (data, nome, descrição)• Informações de Copyright•

Agora veja como todas estas informações são colocadas num cabeçalho:

Exemplo de Cabeçalho Completo

#!/bin/sh # # nome_completo.sh − Busca o nome completo de um usuário no Linux # # Homepage : http://programas.com.br/nomecompleto/ # Autor : João da Silva <[email protected]> # Mantenedor: Maria da Silva <[email protected]> # # −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− # Este programa recebe como parâmetro o login de um usuário e # procura em várias bases qual o seu nome completo, retornando # o resultado na saída padrão (STDOUT). # # Exemplos: # $ ./nome_completo.sh jose # José da Silva # $ ./nome_completo.sh joseee # $ # # A ordem de procura do nome completo é seqüencial: # # 1. Arquivo /etc/passwd # 2. Arquivo $HOME/.plan # 3. Base de Usuários LDAP # 4. Base de Usuários MySQL # # Respeitando a ordem, o primeiro resultado encontrado será o # retornado. # −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− # # # Histórico: # # v1.0 1999−05−18, João da Silva: # − Versão inicial procurando no /etc/passwd # v1.1 1999−08−02, João da Silva: # − Adicionada pesquisa no $HOME/.plan # − Corrigido bug com nomes acentuados # v2.0 2000−04−28, Mário Pereira: # − Corrigidos 2.534 bugs (O João não sabe programar!) # − Adicionado meu nome em vários lugares hehehe

AULA 2 − Programas Não São Scripts

13 Dono: Flávio Cunha

Page 18: Apostila Shell Flavio

# v2.1 2000−04−30, José da Silva: # − Desfeitas as "correções" do Mário (ele quebrou o programa) # − Retirada a string "Mário é o Maior" de várias partes # v2.2 2000−05−02, José da Silva: # − Adicionado suporte a LDAP (que trabalheira!) # − Aceita nomes de usuários EM MAIÚSCULAS # − Retirado suporte a acentuação (estraga meu terminal) # v2.3 2000−05−03, José da Silva: # − Arrumado o suporte a LDAP (agora vai funcionar) # v2.4 2000−05−03, José da Silva: # − Arrumado o suporte a LDAP (agora é pra valer) # v2.5 2000−05−04, José da Silva: # − Retirado o suporte a LDAP (eu odeio LDAP!) # v3.0 2000−05−10, Maria da Silva: # − Programa reescrito do zero # − Adicionado suporte a LDAP (funcional) # − Adicionado suporte a MySQL # − Restaurado suporte a acentuação # v3.1 2003−05−10, Maria da Silva: # − Adicionado este comentário para comemorar 3 anos sem # alterações :) # # # COPYRIGHT: Este programa é GPL. #

Ficou extenso? Sim! Isso é ruim? Não!

Numa primeira olhada pode parecer "feio" um cabeçalho grande. De fato, às vezes o cabeçalho pode ficar atémaior que o Programa... Mas isso não é um problema, pois para o interpretador, os comentários são apenasignorados, não influindo no desempenho. Já para o programador que precisar modificar o código, quantadiferença! E cuidado, este programador pode ser você mesmo.

Antes de mergulhar no código, é importante ter uma visão geral do programa, o que facilita muito a suaanálise. Não acredita? Então que tal descrever o que faz este programa?

Programa Misterioso

#!/bin/bash o=+ a=1 z=${1:−1}; [ "$2" ] && { a=$1; z=$2; } ; [ $a −gt $z ] && o=− while [ $a −ne $z ]; do echo $a ; eval "a=\$((a$o 1))"; done; echo $a

Complicado né? :)

Mesmo executando este programa, ainda assim é difícil dizer precisamente o que ele e faz em todos osdetalhes. Que falta faz um cabeçalho! Não dá pra saber nem o nome do programa, tudo o que se sabe é queele roda no Bash, por causa da primeira linha.

Analise a diferença. Como está agora:

O autor escreveu o código e não se importou em escrever um cabeçalho. O Programa é dele,funciona para ele.

O programador que "cair de pára−quedas" no código, e precisar modificá−lo, vai gastar mais de 10minutos só para entender o que ele faz e para quê ele serve.

O usuário que encontrar seu Programa vai simplesmente ignorá−lo, pois não saberá pra quê serve enem como utilizá−lo.

Por outro lado, a situação poderia ser diferente:

O autor escreveu o código e investiu mais 10 minutos para escrever um cabeçalho descritivo,enquanto toda a idéia está fresca em sua cabeça.

O programador que "cair de pára−quedas" no código, e precisar modificá−lo, vai gastar 1 minuto paraler o cabeçalho e vai imediatamente saber o que o Programa faz e para quê ele serve.

O usuário que encontrar seu Programa vai ler o cabeçalho e saber o que ele faz, podendo utilizá−lotranqüilamente.

AULA 2 − Programas Não São Scripts

14 Dono: Flávio Cunha

Page 19: Apostila Shell Flavio

Ou seja, não é trabalho algum para o autor escrever um texto simples, com exemplos. Já para quem precisarolhar o código, ter o cabeçalho pode ser a diferença entre uma apresentação imediata ao Programa, ou tempoperdido em testes e análises apenas para saber "do que se trata".

Que tal inchar um programa de 3 linhas para 23, e torná−lo mais amigável?

Programa Misterioso com Cabeçalho

#!/bin/bash # # seq.sh − Emulação do comando seq em Bash, por Aurélio M. Jargas # # O comando seq recebe dois números e mostra na saída padrão todos os # números existentes entre eles, numa seqüência pronta para ser usada # pelo comando 'FOR'. Caso omitido o número inicial, é utilizado o 1. # # Exemplo1 Exemplo2 Exemplo3 # # $ seq 5 10 $ seq 10 5 $ seq 5 # 5 10 1 # 6 9 2 # 7 8 3 # 8 7 4 # 9 6 5 # 10 5 # # Uso em scripts: for i in `seq 5 10`; do comandos ; done #

o=+ a=1 z=${1:−1}; [ "$2" ] && { a=$1; z=$2; } ; [ $a −gt $z ] && o=− while [ $a −ne $z ]; do echo $a ; eval "a=\$((a$o 1))"; done; echo $a

Ahhhhhh, agora sim!

Uma lida rápida no cabeçalho já nos dá todas as informações necessárias para entender o que ele faz. Eainda, com os exemplos, também temos instruções de como utilizá−lo.

Então, vale ou não vale a pena aumentar o tamanho do Programa para facilitar sua manutenção? Claro quevale!

AULA 2 − Programas Não São Scripts

15 Dono: Flávio Cunha

Page 20: Apostila Shell Flavio

Como Escrever Código Limpo

O Programa seq.sh visto no tópico anterior já possui um cabeçalho bem descritivo do que ele faz. Mas logoapós, temos duas linhas que poderiam ser definidas como "sopa de letrinhas", pois vários comandos foramajuntados numa massa de caracteres difícil de se digerir.

Para que um Programa seja legível por humanos, o seu código deve ser limpo, ou seja, deve estarvisualmente bem organizado para facilitar a leitura.

Existem várias regras simples para melhorar o código e torná−lo legível, bonito até. Note que estas regrasdizem respeito a posicionamento do código apenas, nenhum comando ou nome de variável precisa seralterado.

Regras de um Código Visualmente Limpo

Colocar apenas um comando por linha• Alinhar verticalmente comandos de um mesmo bloco, usando espaços ou TABs• Deslocar o alinhamento à direita a cada bloco novo• Usar linhas em branco para separar trechos• Não ultrapassar o limite de 80 colunas por linha•

Todas estas regras são facilmente aplicadas apenas inserindo espaços (ou TABs) e quebras de linha. Vamosver a "transformação" pela qual o código sopa de letrinhas vai passar:

seq.sh sujo:

o=+ a=1 z=${1:−1}; [ "$2" ] && { a=$1; z=$2; } ; [ $a −gt $z ] && o=− while [ $a −ne $z ]; do echo $a ; eval "a=\$((a$o 1))"; done; echo $a

seq.sh limpo:

o=+ a=1 z=${1:−1}

[ "$2" ] && { a=$1 z=$2 }

[ $a −gt $z ] && o=−

while [ $a −ne $z ]; do echo $a eval "a=\$((a$o 1))" done

echo $a

Quanta diferença hein? O Programa é exatamente o mesmo, porém os espaços em branco adicionados otornaram fácil de ler, e por que não dizer até charmoso &:)

Basicamente os separadores ponto−e−vírgula foram trocados por quebras de linha, os comandos dos blocos{...} e while foram alinhados e deslocados por um TAB e várias linhas em branco foram adicionadas paraseparar o código em partes distintas.

Não há segredo algum em limpar o código, basta fazer!

Para o deslocamento pode−se usar espaços em branco ou TABs, tanto faz. Fica a critério do programadorescolher. Os TABs são mais flexíveis por que os editores de texto bons têm opções para trocar o "tamanho"de um TAB, podendo ser 8 espaços (o padrão) ou qualquer outra quantidade que se queira.

Para comandos muito extensos que podem ultrapassar 80 colunas, basta "escapar" a quebra de linha econtinuar o comando na linha seguinte. O Dialog é um comando que usa linhas bem compridas.

AULA 2 − Programas Não São Scripts

16 Dono: Flávio Cunha

Page 21: Apostila Shell Flavio

dialog −−title "Minha telinha" −−msgbox "Esta é a minha mensagem" 0 0

Ele também pode ser escrito assim:

dialog −−title "Minha telinha" \ −−msgbox "Esta é a minha mensagem" \ 0 0

Como Comentar um Programa

Já foi visto por que é importante o Programa ter um cabeçalho completo. Já foi visto como limpar o código,tornando−o legível. Mas isso ainda não é o suficiente para que o Programa seja fácil de se alterar.

Mesmo estando o seq.sh já limpo e com cabeçalho, ainda podem restar perguntas como:

O que faz exatamente essa linha?• Qual a função desse trecho do código?• Por que foi usado o comando X ao invés do Y?• Por que é feito esse teste aqui?•

Para o autor as respostas podem parecer óbvias, mas para o resto do mundo que não codificou aquelePrograma do zero, podem aparecer muitas dúvidas.

Código é código. O computador sempre o executará corretamente estando limpo ou não. Mas para oshumanos, nenhum código substituirá o bom e velho português, que é a língua que dominamos. Então nãoseria bom misturar textos explicativos em português no meio do código?

É para isso existem os comentários, eles são uma maneira do programador deixar "recados" no código,explicar o que faz uma linha ou um bloco e até deixar lembretes para ele mesmo ler depois.

Existem quatro tipos comuns de comentários em Shell:

Comentário em Bloco, para introduzir uma seção

############################################################### # # # Este é um comentário em bloco. # # # # Visualmente distinto dos comandos, serve para colocar # # textos extensos, introduções e exemplos. # # # # Fazer o bloco tipo uma "caixa fechada" é opcional. # # # ###############################################################

1.

Comentários de uma linha para blocos

### Aqui começa o trecho que extrairá o e−mail do usuário

2.

Comentários de uma linha para comandos

# A linha seguinte retira o '@' do e−mail

3.

Comentários de meia linha para comandos

echo "$email" # Mostra o e−mail na tela

4.

O Shell simplesmente ignora os comentários, então nunca é demais colocá−los. Eles podem ser resumidospara ocupar meia linha, ou podem ser tão extensos quanto necessário para explicar um trecho complexo.

O bom programador, além de escrever códigos inteligentes e eficientes, deve saber colocar comentáriosrelevantes e claros para completar a obra.

Vamos ver o nosso Programa de exemplo completo, com cabeçalho, e comentários?

AULA 2 − Programas Não São Scripts

17 Dono: Flávio Cunha

Page 22: Apostila Shell Flavio

seq.sh limpo e comentado:

#!/bin/bash # # seq.sh − Emulação do comando seq em Bash, por Aurélio M. Jargas # # O comando seq recebe dois números e mostra na saída padrão todos os # números existentes entre eles, numa seqüência pronta para ser usada # pelo comando 'FOR'. Caso omitido o número inicial, é utilizado o 1. # # Exemplo1 Exemplo2 Exemplo3 # # $ seq 5 10 $ seq 10 5 $ seq 5 # 5 10 1 # 6 9 2 # 7 8 3 # 8 7 4 # 9 6 5 # 10 5 # # Uso em scripts: for i in `seq 5 10`; do comandos ; done #

### Inicialização das variáveis o=+ # Operação a ser feita. Pode ser + ou − a=1 # Valor padrão de início da contagem z=${1:−1} # Valor do final da contagem recebido em $1 (padrão é 1)

# A variável 'a' é o número de início e a variável 'z' é o final. # # O código acima serve para quando o usuário passar apenas um valor na # linha de comando, que seria o valor do *final* da contagem. Por isso # a=1 e z=$1. # # Caso o programa seja chamado sem parâmetros, 'z' também é definido # como 1. Como a=1 e z=1, o programa retorna apenas o número 1.

[ "$2" ] && {

# Foram passados 2 parâmetros, o $1 é o início e o $2 é o fim. a=$1 z=$2 }

### # Se o número de início ($a) for maior que o número de final ($z), # faremos uma contagem regressiva, por isso a operação é definida # como subtração. # [ $a −gt $z ] && o=−

### # Loop da contagem (progressiva ou regressiva) # # A cada volta, adiciona ou subtrai 1 do valor inicial, # até que ele se iguale ao final. # # O eval executa o resultado da expansão de variáveis. # Supondo o='+' e a=3, o eval executará o comando a=$((3+1)). # while [ $a −ne $z ]; do echo $a # mostra a contagem atual eval "a=\$((a$o 1))" # efetua a operação (+1 ou −1) done

echo $a # mostra o último número

Uau! O antigo "programa misterioso sopa de letrinhas" que tinha apenas 3 linhas agora é um Programão demais de 60 linhas e perfeitamente legível. E note que nenhum comando foi alterado, apenas brancos ecomentários foram adicionados.

AULA 2 − Programas Não São Scripts

18 Dono: Flávio Cunha

Page 23: Apostila Shell Flavio

Vamos até relembrá−lo para ver a diferença. E que diferença!

#!/bin/bash o=+ a=1 z=${1:−1}; [ "$2" ] && { a=$1; z=$2; } ; [ $a −gt $z ] && o=− while [ $a −ne $z ]; do echo $a ; eval "a=\$((a$o 1))"; done; echo $a

Não tem comparação. Códigos compactos são interessantes, intrigantes. Mas na vida real onde não se podeperder tempo analisando maçarocas, o código limpo e comentado é uma necessidade.

Só para completar, existem três tipos especiais de comentários, que são prefixos largamente utilizados emtodas as linguagens, com significados especiais. Eles servem para a comunicação entre programadores oumesmo como lembretes feitos pelo autor para ele mesmo ler depois:

Tipos especiais de comentário

TODO: Indica uma tarefa a ser feita, uma pendência ainda não resolvida. Exemplo:

#TODO Colocar este trecho numa função

FIXME: Indica um bug conhecido, que precisa ser arrumado. Exemplo:

#FIXME Este loop não está funcionando para números negativos

XXX: Chama a atenção para o comentário seguinte, é um recado ou uma notícia importante. Exemplo:

#XXX Não sei como melhorar esse trecho, me ajudem!!!

Antes de terminar o assunto, alguns detalhes sobre comentários:

Deve−se comentar em português ou inglês?Como regra geral, comente em português, que é a língua falada. Em inglês, apenas se há previsão doprograma ser disponibilizado internacionalmente ou se for um requisito de projeto (isso é muitocomum em empresas multinacionais).

Deve−se usar acentuação?Sim! A acentuação não é problema na grande maioria dos sistemas e ambientes atuais, e o portuguêsfoi feito para ser acentuado. Salvo situações específicas onde limitações do ambiente proíbem osacentos, acentue sempre!

Como deve ser o texto de um comentário?Curto, direto ao ponto, claro, relevante, contextualizado, sem erros de ortografia e gramática. Dêrespostas ao invés de complicar mais, antecipe possíveis dúvidas do leitor e principalmente:mantenha atualizado. Melhor nenhum comentário do que um comentário errado.

Faz mal comentar demais?Sim. Não coloque comentários irrelevantes, de coisas óbvias para qualquer programador. Umexemplo: a='abc' # Define 'a' com 'abc'. Também não faça dos comentários um canal deexpressão de sua angústia ou um local para autopromoção. Os comentários devem falar somentesobre o código, e não sobre o autor dele.

E como mensagem final, um conselho famoso, que nunca deve ser esquecido:

"Don't comment bad code, rewrite it."

Ou seja, não perca tempo escrevendo mil comentários para tentar explicar um trecho de código obscuro e malfeito. É melhor reescrever o código de maneira limpa.

AULA 2 − Programas Não São Scripts

19 Dono: Flávio Cunha

Page 24: Apostila Shell Flavio

Hora de Reavaliar Seus Conceitos

É hora de deixar as manias de scripteiro para trás e evoluir. O bom programador é disciplinado e segue asregras, por saber o valor delas. Começaremos com regras básicas, sobre variáveis e funções.

Uso Racional de Variáveis

Não totalmente relacionado ao assunto de limpeza de código, o uso racional de variáveis acaba sendo umaparte importante do mesmo, pois influi diretamente na legibilidade do código.

Variáveis são simples, mas nem todos sabem como ou quando utilizá−las. Algumas dicas importantes:

Como nomear variáveis

Dê um nome descritivo para cada variável• Use apenas letras, números e o sublinhado "_"• Prefira MAIÚSCULAS para variáveis globais e minúsculas pra variáveis locais e temporárias• Decida usar somente português ou somente inglês para nomear as variáveis, não misture!• Acentuação não faz parte do nome de uma variável. Ponto final.• $var1, $var2 e $var3 são definitivamente péssimos nomes para variáveis• $a, $m e $x também não ajudam•

Quando criar uma variável

Quando precisar usar o mesmo texto ou número duas ou mais vezes• Quando seu programa tiver dados que podem ser modificados pelo usuário• Quando perceber que um texto um dia poderá ser alterado• Quando precisar de configuração de funcionalidades (opções)• Quando precisar ligar/desligar funcionalidades (flags)• Quando quiser (variáveis são legais e dificilmente atrapalham)•

Detalhes sobre variáveis no Shell

Todas são globais, a não ser quando precedidas do comando local• Não são tipadas, então tanto faz a=5, a="5" ou a='5'• As 'aspas simples' impedem a expansão da variável• Podem ser colocadas dentro de aspas duplas junto com strings, "assim $PWD"• Sempre use "aspas duplas" ao redor de variáveis para manter os espaços em branco e evitarproblemas com variáveis vazias

Não é erro referenciar uma variável não existente como $homersimpson• Coloque todas as variáveis importantes no início do Programa, logo após o cabeçalho• Também podem ser acessadas como ${nome} para evitar confusão como em $PWDjoao ou paraacessar mais do que nove parâmetros: ${10}, ${11}, ...

Sempre, sempre cheque o valor de uma variável antes de usá−la em comandos perigosos como rm,mv e dd e quando usando o >

DICA DO DIA: "Variáveis são variáveis! Nunca confie numa!" :)

Fazendo Funções do Jeito Certo

Como nomear funções

Dê um nome descritivo para cada função• Use apenas letras, números e o sublinhado "_"• Aconselha−se iniciar cada palavras com letra maiúscula em nomes de função, Exemplos:PegaValorNumerico e ExtraiNomeUsuario

Decida usar somente português ou somente inglês para nomear as funções, não misture!• Acentuação não faz parte do nome de uma função. Ponto final.• func1, func2 e func3 são definitivamente péssimos nomes para funções• a, m e x também são um horror•

AULA 2 − Programas Não São Scripts

20 Dono: Flávio Cunha

Page 25: Apostila Shell Flavio

Quando criar uma função

Quando precisar usar o mesmo trecho de código duas ou mais vezes• Quando quiser colocar em destaque um trecho de código especialista• Quando precisar de recursividade• Quando quiser (funções sempre ajudam)•

Detalhes sobre funções no Shell

Sempre use o comando local para proteger as variáveis da função• Funções são como comandos do sistema, podendo ser chamadas diretamente pelo nome• A função chamada "ls" tem preferência ao comando "ls"• Sempre coloque todas as funções no início do Programa, logo após as variáveis• Uma função deve ser declarada antes de ser chamada (a ordem importa)• Funções só podem retornar números de 0 a 255, usando o comando return• Funções podem retornar strings usando o comando echo• Funções podem gravar variáveis globais (mas evite fazer isso)•

AULA 2 − Programas Não São Scripts

21 Dono: Flávio Cunha

Page 26: Apostila Shell Flavio

AULA 3 − Explorando as Possibilidades do Shell

Programação envolvendo Chaves (Flags)

Usar Flags é uma das maneiras mais tranqüilas de se programar. O conceito é simples, e se bem aplicado,deixa o programa legível e fácil de entender.

Uma Chave (Flag), é uma variável de apenas dois estados: ou está ligada, ou não. Funciona exatamentecomo um interruptor de luz, onde só há dois estados: a lâmpada está acesa ou apagada, não existindo "meioacesa" ou "meio apagada".

Este esquema de estados é usado para ligar e desligar atributos e funcionalidades em um programa. Porexemplo, se seu programa mostra uma mensagem na tela, e é opcional para o usuário escolher umamensagem colorida ou sem cores, uma Chave interna do programa seria a responsável por guardar essainformação. Ela estaria no início do programa:

USAR_CORES=0 # Coloque 1 para ligar as cores

No exemplo, o zero é a opção padrão e indica que a chave das cores está desligada. Para ligá−la, o usuáriodeve trocar o zero pelo número um. Mais à frente no programa, haverá um trecho para checar o estado dessachave, como:

if [ $USAR_CORES −eq 1 ]; then msg_colorida $mensagem # chama a função "msg_colorida" else echo $mensagem # usa o echo normal fi

Então a chave nada mais é do que uma variável normal. A diferença é que o seu valor tem significado especialpara o programa, podendo mudar o rumo da execução ou ativar/desativar funcionalidades.

Dessa maneira, pode−se colocar várias chaves para controlar vários aspectos do programa, e apenasdefinindo valore pode−se alterar todo o comportamento da execução.

Chaves como Configuração pelo Usuário

É aconselhável colocar todas as chaves no início do programa, como o primeiro trecho após o cabeçalho.Dessa maneira, tem−se uma "configuração" facilitada, separada visualmente do código.

Aliado a comentários descritivos, o uso das chaves é uma maneira limpa e amigável de se ter um programacom configuração, onde o usuário pode alterar seu funcionamento sem precisar entender de programação.Exemplo:

### Configuração do programa mostra_mensagem.sh ### Use 0 (zero) para desligar as opções e 1 (um) para ligar ### O padrão é zero para todas (desligado) # USAR_CORES=0 # mostrar cores nas mensagens? CENTRALIZAR=0 # centralizar a mensagem na tela? SOAR_BIPE=0 # soar um bipe ao mostrar a mensagem? CONFIRMAR=0 # pedir confirmação antes de mostrar? MOSTRA_E_SAI=0 # sair do programa após mostrar? # ### Fim da configuração − Não edite daqui para baixo

Fácil de entender não? Qualquer pessoa que saiba usar um editor de textos conseguirá configurar o programaàs suas necessidades.

Teste Mais Robusto

Mas voltando ao exemplo do teste do estado da chave, essa foi a linha utilizada:

if [ $USAR_CORES −eq 1 ]; then

22 Dono: Flávio Cunha

Page 27: Apostila Shell Flavio

Temos uma fraqueza enorme aqui. Ao usar o −eq estamos assumindo uma comparação numérica. E se aoinvés de zero ou um o usuário colocar um texto como "abc", ou deixar a variável vazia?

[: abc: integer expression expected

[: −eq: unary operator expected

Erro! O usuário pode quebrar o funcionamento do programa. Para solucionar este problema, deve−se fazeruma comparação de strings e não numérica:

if [ "$USAR_CORES" = 1 ]; then

O −eq foi trocado para o sinal de igual, que compara strings, e a chave foi colocada entre aspas duplas, paraevitar erro quando ela estiver vazia.

Agora temos uma chave robusta, que liga quando seu valor for 1 e desliga em qualquer outro valor, sejastring, numérico ou não definido.

Valor Estado da chave

USAR_CORES="abc" Chave DESLIGADA

USAR_CORES="" Chave DESLIGADA

USAR_CORES= Chave DESLIGADA

USAR_CORES="1" Chave LIGADA

USAR_CORES=0 Chave DESLIGADA

USAR_CORES=2 Chave DESLIGADA

USAR_CORES=1 Chave LIGADA

Chaves Internas

Depois de ler todas as configurações do usuário, o programa pode tomar decisões analisando os estadosdessas chaves. Essas decisões podem ser simples ou complexas, dependendo da própria estrutura e uso daschaves.

É possível fazer um esquema de relacionamento entre chaves, onde certas funcionalidades dependem deoutras, ou das capacidades do sistema atual. Outros fatores relevantes que podem influir na tomada dedecisões são: o nível de acesso do usuário ao sistema, o horário da execução ou o estado atual do sistema.

O resultado dessa análise, são as decisões tomadas pelo programa. Uma maneira eficiente de guardar essasdecisões, é novamente utilizar chaves. Além das chaves que o usuário tem acesso, o programa pode tervárias outras chaves internas, que são definidas apenas no momento da execução, e refletem as decisõestomadas pelos algoritmos.

Podemos chamar essa fase do programa de "bateria de testes", em que o objetivo é apenas analisar e tomardecisões, nada de processamento por enquanto. Somente depois de todas as chaves internas definidas é queo processo se inicia.

AULA 3 − Explorando as Possibilidades do Shell

23 Dono: Flávio Cunha

Page 28: Apostila Shell Flavio

Com todas as chaves relevantes definidas, fica fácil codificar o processamento, pois há um universo limitadode possibilidades e combinações. Vários IFs, controlando várias condições, conseguem fazer muito demaneira razoavelmente simples e de manutenção facilitada.

Detalhes Sobre o Nome da Chave

Além da configuração e armazenamento de decisões, o uso de chaves também torna o código mais legível, eos algoritmos mais fáceis de entender. Quanto mais descritivo e claro o nome da chave, mais rápido deentender para que ela serve.

Inclusive, se os nomes das chaves forem bem amigáveis como "GRAVAR_LOG_EM_ARQUIVO" ou"ESCONDER_MENSAGENS_DE_ERRO", nem é preciso colocar comentários para explicar seu propósito. Autilização de letras maiúsculas é recomendada, pois as chaves são variáveis "globais", que não serãoalteradas no processamento.

A língua inglesa tende a ser mais concisa e universal para nomes de chaves, como "SAVE_LOGFILE" e"HIDE_ERROR_MSGS" para os exemplos anteriores. Mas aconselha−se que o nome das chaves siga opadrão das outras variáveis do programa.

Outra tática muito usada para separar as variáveis normais das chaves, é utilizar prefixos no nome. É comumcomeçar nomes de chaves com "CH_" ou "F_" (de chave ou flag) para diferenciá−las. Nesse caso as chaves jácitadas ficariam: "F_SAVE_LOGFILE" e "F_HIDE_ERROR_MSGS".

A vantagem da utilização do prefixo é que para o programador fica mais visual e prático saber que todas asvariáveis iniciadas por "F_" são chaves e só estarão "ativadas" se seu valor for "1".

Como Depurar Programas (Debug)

A depuração de programas é uma característica útil para encontrar erros e imperfeições, pois mostra o queacontece "por trás das cortinas" durante a execução.

Em Shell, temos várias maneiras de depurar programas, desde simples echos colocados estrategicamenteaté execução passo−a−passo e depuração personalizada com funções. Vamos conhecê−las!

Primeiro, precisamos de um programa com defeito para podermos depurar, aqui está:

O Programa que Não Funciona

#!/bin/sh # bug.sh − Mostra a mensagem ".....Oi, TUDO BEM?" na tela

TXT1='Oi' TXT2='tudo bem?'

AULA 3 − Explorando as Possibilidades do Shell

24 Dono: Flávio Cunha

Page 29: Apostila Shell Flavio

TXT1=" $TXT1" # Adiciona 5 espaços antes do Oi TXT1=`echo $TXT1 | tr ' ' .` # Troca os espaços por pontos TXT2=`echo $TXT2 | tr a−z A−Z` # Deixa o TXT2 em maiúsculas echo "$TXT1, $TXT2" # Mostra a mensagem

O código é bem simples, e aparentemente correto. O programa deveria mostrar a mensagem ".....Oi, TUDOBEM?", mas ao executar...

$ ./bug.sh Oi, TUDO BEM?

Para onde foram os pontinhos?

Checagem de Sintaxe com a opção −n

Antes de começar a testar a programa, que tal checar se está tudo certo com a sintaxe dos comandos? Aopção −n do Shell faz exatamente isso. É somente uma checagem, os comandos não são executados.

$ sh −n ./bug.sh $

A opção pode ser passada assim via linha de comando, ou então colocada diretamente no programa, naprimeira linha especial:

#!/bin/sh −n

Tanto faz.

Debug usando o comando echo

A maneira mais simples de se depurar um programa falho, é colocar comandos echo para mostrar o conteúdode variáveis importantes no trecho de código problemático.

No nosso exemplo, os pontinhos não foram mostrados, então deve haver algum problema com a variável$TXT1. Basta colocar os comandos echo nos lugares certos:

#!/bin/sh # bug.sh − Mostra a mensagem ".....Oi, TUDO BEM?" na tela

TXT1='Oi' TXT2='tudo bem?'

TXT1=" $TXT1" # Adiciona 5 espaços antes do Oi

echo "TXT1 com espaços: $TXT1"

TXT1=`echo $TXT1 | tr ' ' .` # Troca os espaços por pontos

echo "TXT1 com pontinhos: $TXT1"

TXT2=`echo $TXT2 | tr a−z A−Z` # Deixa o TXT2 em maiúsculas echo "$TXT1, $TXT2" # Mostra a mensagem

Pronto, esses dois devem ser o suficiente. Checando...

$ ./bug.sh TXT1 com espaços: Oi TXT1 com pontinhos: Oi Oi, TUDO BEM?

No ponto do primeiro echo a variável $TXT1 estava com os espaços, porém após o comando que deveriaadicionar os pontos, os espaços sumiram!

Então depurando o programa, foi possível descobrir exatamente em qual linha está o erro:

AULA 3 − Explorando as Possibilidades do Shell

25 Dono: Flávio Cunha

Page 30: Apostila Shell Flavio

TXT1=`echo $TXT1 | tr ' ' .` # Troca os espaços por pontos

Mas ainda não é possível saber qual o erro, pois aparentemente a linha está correta.

Debug com a opção −x (e −v)

Partindo para uma depuração mais agressiva, o Shell possui a opção −x, que mostra na tela os comandoscomo eles são executados, após feitas todas as expansões internas de nomes de arquivo e variáveis.

Para usá−la é o mesmo que o −n já visto: ou coloca−se na primeira linha especial do arquivo, ou chama diretona linha de comando:

$ sh −x ./bug.sh + TXT1=Oi + TXT2=tudo bem? + TXT1= Oi + echo Oi <−−−−−− aqui + tr . + TXT1=Oi + echo tudo bem? + tr a−z A−Z + TXT2=TUDO BEM? + echo Oi, TUDO BEM? Oi, TUDO BEM?

As linhas com os comandos são precedidas pelo sinal de mais (variável PS4) e por elas pode−se ver o queaconteceu. Antes do primeiro comando tr, o echo mostrou apenas "Oi", sem os espaços em branco. Como otr não viu espaços, ele não pôde adicionar os pontinhos.

Para decifrar este erro, basta executar o trecho em questão na linha de comando para ver o que ocorre:

$ TXT1=' Oi'

$ echo $TXT1 Oi

$ echo "$TXT1" Oi

Atenção às Aspas!

Ahhhh, a pegadinha das aspas. Se não "aspear" a variável, os espaços em branco do começo e do final sãocortados e os espaços consecutivos internos são reduzidos a um:

$ TXT=' Oi Tchau '

$ echo $TXT Oi Tchau

Então para corrigir o problema no programa, basta "aspear" a variável $TXT1:

TXT1=`echo "$TXT1" | tr ' ' .` # Troca os espaços por pontos

Testando (cruze os dedos!):

$ ./bug.sh .....Oi, TUDO BEM?

Certo! Aí estão os pontinhos.

Mais Informações Ainda com o −v

Um outro recurso útil para se usar em conjunto com o −x, é a opção −v, que mostra a linha atual doPrograma, a que está sendo executada. Em programas muitos extensos, onde é fácil se perder no meio docódigo, é muito útil depurar usando o −xv. Veja a diferença:

AULA 3 − Explorando as Possibilidades do Shell

26 Dono: Flávio Cunha

Page 31: Apostila Shell Flavio

$ sh −xv ./bug.sh #!/bin/sh # bug.sh − Mostra a mensagem ".....Oi, TUDO BEM?" na tela

TXT1='Oi' + TXT1=Oi TXT2='tudo bem?' + TXT2=tudo bem?

TXT1=" $TXT1" # Adiciona 5 espaços antes do Oi + TXT1= Oi TXT1=`echo "$TXT1" | tr ' ' .` # Troca os espaços por pontos + echo Oi + tr . + TXT1=.....Oi TXT2=`echo $TXT2 | tr a−z A−Z` # Deixa o TXT2 em maiúsculas + echo tudo bem? + tr a−z A−Z + TXT2=TUDO BEM? echo "$TXT1, $TXT2" # Mostra a mensagem + echo .....Oi, TUDO BEM? .....Oi, TUDO BEM?

Numa primeira olhada pode parecer confuso ter tantas informações na tela, mas quando for o seu programaque estiver com um bug cabeludo, essa sopa de letrinhas será bem−vinda &:)

Debug de Trechos Específicos (Liga/Desliga)

Usando o mesmo conceito da tática anterior, é possível ligar o Debug para apenas algumas partes doprograma. A opção continua sendo a −x, porém agora será o comando set quem a ligará e desligará.

set −x

A opção −x para o comando set, faz com que o Debug seja ligado. Todos os comandos posteriores serãoexecutados com mensagens de depuração. Para desligar o Debug a qualquer momento, basta:

set +x

O sinal de mais "+" na frente da opção serve para desligá−la. Exemplo:

$ set −x

$ i=$((3+4)) + i=7

$ echo $i + echo 7 7

$ set +x + set +x

$ i=$((3+4))

$

Execução Passo−a−Passo

Há uma linha mágica, que pode ser colocada no programa para que ele pare a cada linha durante a execução,esperando um ENTER do usuário para executá−la:

trap read DEBUG

Depois de colocada esta linha no programa, basta executá−lo com o −x:

$ bash −x ./bug.sh + trap read DEBUG + TXT1=Oi ++ read

AULA 3 − Explorando as Possibilidades do Shell

27 Dono: Flávio Cunha

Page 32: Apostila Shell Flavio

+ TXT2=tudo bem? ++ read

+ TXT1= Oi ++ read

++ echo ' Oi' ++ tr ' ' . + TXT1=.....Oi ++ read

É simples, é como se o comando read fosse inserido entre as linhas do programa, dando chance ao usuáriode executá−lo passo−a−passo.

Nota: Esta técnica não funciona no Bourne Shell.

Debug Personalizado

Além de todas as opções vistas até agora, depois que o programa atinge um certo nível de complexidade,mostrar a depuração para todas as linhas fica incômodo, e ficar tirando e colocando echos também.

Uma maneira avançada de fazer a depuração, é criar uma função específica para cuidar disso, a Debug():

Debug(){ [ "$DEBUG" = 1 ] && echo "$*" ; }

O que essa função faz, é mostrar a mensagem de depuração somente se a variável global $DEBUG estiverdefinida e com o valor 1. Assim o programador pode ligar e desligar a depuração simplesmente trocando ovalor de uma variável. Vejamos como fica o nosso programa de exemplo utilizando a função de depuração:

#!/bin/sh # bug.sh − Mostra a mensagem ".....Oi, TUDO BEM?" na tela

DEBUG=1 # depuração: 0 desliga, 1 liga

TXT1='Oi' TXT2='tudo bem?'

# função de depuração Debug(){ [ "$DEBUG" = 1 ] && echo "$*" ; }

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

TXT1=" $TXT1" # Adiciona 5 espaços antes do Oi

Debug "TXT1 com espaços: $TXT1"

TXT1=`echo "$TXT1" | tr ' ' .` # Troca os espaços por pontos

Debug "TXT1 com pontinhos: $TXT1"

TXT2=`echo $TXT2 | tr a−z A−Z` # Deixa o TXT2 em maiúsculas echo "$TXT1, $TXT2" # Mostra a mensagem

O conceito é simples, a implementação é simples e é super útil. E pode ficar ainda melhor, pois com asmensagens centralizadas nessa função, é possível formatá−las de maneira uniforme, como por exemploadicionar um prefixo padrão para que elas fiquem bem visíveis:

Debug(){ [ "$DEBUG" = 1 ] && echo "−−−−−−−−DEBUG: $*" ; }

Ou ainda, adicionar cores usando caracteres de controle:

Debug(){ [ "$DEBUG" = 1 ] && echo −e "\033[33;1m−−− $*\033[m" ; }

Não se preocupe (ainda) com os caracteres de controle. Eles serão vistos na próxima Aula.

AULA 3 − Explorando as Possibilidades do Shell

28 Dono: Flávio Cunha

Page 33: Apostila Shell Flavio

Debug Personalizado e Categorizado

Nesse momento você já é um expert em depuração, já tem a sua função Debug() toda turbinada e há vários"pontos de depuração" no programa. Mas você quer mais. Já há tantas mensagens de depuração que estáficando confuso novamente. Seria bom poder "categorizar" essas mensagens e mostrar apenas algumas enão todas.

Seus problemas acabaram! Com uma pequenina modificação na função Debug(), é possível categorizar asmensagens:

Debug(){ [ $1 −le $DEBUG ] && echo "−−− DEBUG $*" ; }

Ou seja, agora a função mostra a mensagem caso o $1 seja menor ou igual a $DEBUG. Então na chamadadessa função, o primeiro parâmetro deve ser um número:

Debug 2 Mensagem nível dois

E caso $DEBUG for igual a dois, três ou mais, a mensagem será mostrada. Com este esquema, basta oprogramador se organizar e colocar os números certos em cada chamada da função. Sugestão:

Nível Descrição

1 Mensagens genéricas, de localização ("estou aqui")

2 Mensagens de localização de fluxo ("entrei no loop")

3 Mensagens com conteúdo de variáveis importantes

4 Mensagens com conteúdo de variáveis secundárias

Partindo de mensagens genéricas para específicas, quanto maior for o valor de $DEBUG, mais mensagens dedepuração aparecerão na tela. Um exemplo completo:

#!/bin/bash # debug−categorizado.sh − Exemplo de Debug em níveis

DEBUG=${1:−0} # passe o nível pelo $1

Debug(){ [ $1 −le $DEBUG ] && echo "−−− DEBUG $*" ; }

Debug 1 "Início do Programa" i=0 max=5 echo "− Contando até $max −"

Debug 2 "Vou entrar no WHILE" while [ $i −ne $max ]; do Debug 3 "Valor de \$i antes de incrementar: $i" let i=$i+1 Debug 3 "Valor de \$i depois de incrementar: $i" echo "Contando: $i..." done Debug 2 "Saí do WHILE"

echo 'Terminei!' Debug 1 "Fim do Programa"

Como ele se comporta em ação:

$ ./debug−categorizado.sh − Contando até 5 − Contando: 1... Contando: 2... Contando: 3... Contando: 4... Contando: 5... Terminei!

AULA 3 − Explorando as Possibilidades do Shell

29 Dono: Flávio Cunha

Page 34: Apostila Shell Flavio

$ ./debug−categorizado.sh 1 −−− DEBUG 1 Início do Programa − Contando até 5 − Contando: 1... Contando: 2... Contando: 3... Contando: 4... Contando: 5... Terminei! −−− DEBUG 1 Fim do Programa

$ ./debug−categorizado.sh 3 −−− DEBUG 1 Início do Programa − Contando até 5 − −−− DEBUG 2 Vou entrar no WHILE −−− DEBUG 3 Valor de $i antes de incrementar: 0 −−− DEBUG 3 Valor de $i depois de incrementar: 1 Contando: 1... −−− DEBUG 3 Valor de $i antes de incrementar: 1 −−− DEBUG 3 Valor de $i depois de incrementar: 2 Contando: 2... −−− DEBUG 3 Valor de $i antes de incrementar: 2 −−− DEBUG 3 Valor de $i depois de incrementar: 3 Contando: 3... −−− DEBUG 3 Valor de $i antes de incrementar: 3 −−− DEBUG 3 Valor de $i depois de incrementar: 4 Contando: 4... −−− DEBUG 3 Valor de $i antes de incrementar: 4 −−− DEBUG 3 Valor de $i depois de incrementar: 5 Contando: 5... −−− DEBUG 2 Saí do WHILE Terminei! −−− DEBUG 1 Fim do Programa

E claro, a função Debug() pode crescer tanto quanto se deseje. É possível gravar as mensagens em arquivo,usar uma cor diferente para cada nível, soar o bipe, etc etc etc.

Fazendo Programas −−com −−opções

A grande maioria dos programas do UNIX/Linux funcionam com diversas opções recebidas via linha decomando, geralmente iniciadas pelo hífen "−". São estas opções que modificam o comportamento doprograma, e que informam dados necessários ao seu funcionamento.

Os Formatos Utilizados

Os aplicativos GNU, que são a grande maioria das ferramentas disponíveis nas maiores distribuições de Linuxatuais, seguem a seguinte filosofia para o formato das opções:

Formato das Opções de Aplicativos GNU

Formato Exemplos Descrição

−<letra> −h, −V Opções curtas, de uma letra

−−<palavra> −−help, −−version Opções longas, de uma ou mais palavras

Já no UNIX, pela falta de um padrão, é variada a forma como que os programas esperam receber as opçõesde linha de comando. A maioria usa o mesmo formato GNU, mas algumas ferramentas antigas não:

Outros Formatos Encontrados

Comando Formato Exemplos

find −<palavra> −name,−type

AULA 3 − Explorando as Possibilidades do Shell

30 Dono: Flávio Cunha

Page 35: Apostila Shell Flavio

ps <letra> a u w x

dd <palavra>= if=,of=,count=

E o Shell?

Em Shell, há duas maneiras de fazer um programa "entender" opções via linha de comando:

Fazer uma rotina de leitura "na mão"• Usar o comando getopts•

Cada um tem seus prós e contras, mas em resumo: se o programa só utilizar opções curtas e o getoptsestiver disponível, use−o. Senão, faça a rotina na mão. Vamos aos detalhes:

Os Prós e Contras

getopts na mão

Não funciona no Bourne Shell Funciona em qualquer Shell

Aceita somente opções simples (−−longo não éválido)

Aceita opções curtas −c e −−longas

Aceita várias opções juntas −hVxÉ complicado fazer aceitar várias opções juntas−hVx

Mostra erro em inglês na tela (OPTERR=0 pradesligar)

Os erros podem ser personalizados

As opções válidas devem ser registradas em doislugares

As opções válidas são registradas somente em umlugar

Exemplos Com Opções Curtas

Exemplo com o getopts

#!/bin/bash # parametros−getopts.sh − teste do comando getopts (bash) # 2003−07−25 Aurelio Marinho Jargas

# Função que mostra a tela de ajuda e sai Uso(){ echo " uso: $0 [OPÇÕES]

OPÇÕES: −m MSG Mostra a mensagem MSG na tela −h Mostra esta tela de ajuda −V Mostra a versão do programa " exit 0 }

# Loop nas opções recebidas na linha de comando # As opções válidas são 'hVm:', que são −h, −V e −m # Como é 'm:', isso significa que ele deve receber um argumento # A variável $OPTARG guarda o argumento da opção # while getopts "hVm:" opt; do case $opt in h) Uso;; V) echo $0 versão 0.1;; m) echo "$OPTARG";; *) echo ERRO: Opção desconhecida ou Falta Argumento;; esac done

AULA 3 − Explorando as Possibilidades do Shell

31 Dono: Flávio Cunha

Page 36: Apostila Shell Flavio

Exemplo "na mão"

#!/bin/sh # parametros.sh − exemplo de como ler os parâmetros recebidos # 2003−07−25 Aurelio Marinho Jargas

# Função que mostra a tela de ajuda e sai Uso(){ echo " uso: $0 [OPÇÕES]

OPÇÕES: −m MSG Mostra a mensagem MSG na tela −h Mostra esta tela de ajuda −V Mostra a versão do programa " exit 0 }

# Erro de falta de argumento FaltaArg(){ echo "Faltou o argumento para a opção $1" exit 1 }

# Loop nas opções recebidas na linha de comando # Após processada uma opção, o shift é usado para passar # para a próxima # while [ "$1" ]; do case $1 in −h) Uso;; −V) echo $0 versão 0.1;; −m) [ "$2" ] || FaltaArg $1 ; echo "$2"; shift;; *) echo ERRO: Opção desconhecida $1;; esac shift done

Executando os Exemplos

Quando tudo está bem, ambos os programas funcionam exatamente igual:

$ ./parametros.sh −h

uso: ./parametros.sh [OPÇÕES]

OPÇÕES: −m MSG Mostra a mensagem MSG na tela −h Mostra esta tela de ajuda −V Mostra a versão do programa

$ ./parametros.sh −V ./parametros.sh versão 0.1

$ ./parametros.sh −m 'Estou Funcionando!' Estou Funcionando!

Mas quando há erro, tem diferença. Com o getopts, para saber qual a opção inexistente ou que faltaparâmetro, é preciso deixar ligada a mensagem de erro padrão (OPTERR=1, já ligada normalmente), só queela está em inglês. Já quando implementando a rotina na mão, tem−se a liberdade de formatar a mensagemcomo quiser.

$ ./parametros.sh −X ERRO: Opção desconhecida −X

$ ./parametros.sh −m Faltou o argumento para a opção −m

$ ./parametros−getopts.sh −X

AULA 3 − Explorando as Possibilidades do Shell

32 Dono: Flávio Cunha

Page 37: Apostila Shell Flavio

./parametros−getopts.sh: illegal option −− X ERRO: Opção desconhecida ou Falta Argumento

$ ./parametros−getopts.sh −m ./parametros−getopts.sh: option requires an argument −− m ERRO: Opção desconhecida ou Falta Argumento

Exemplo Com Opções Longas

Usando getopts, não é possível fazer programas que aceitem opções longas. Por outro lado, naimplementação manual isso é trivial, bastando adicionar mais itens no case:

#!/bin/sh # parametros−longos.sh − exemplo de como ler parâmetros longos # 2003−07−25 Aurelio Marinho Jargas

# Função que mostra a tela de ajuda e sai Uso(){ echo " uso: $0 [OPÇÕES]

OPÇÕES: −m, −−message MSG Mostra a mensagem MSG na tela −h, −−help Mostra esta tela de ajuda −V, −−version Mostra a versão do programa " exit 0 }

# Erro de falta de argumento FaltaArg(){ echo "Faltou o argumento para a opção $1" exit 1 }

# Loop nas opções recebidas na linha de comando # Após processada uma opção, o shift é usado para passar # para a próxima # while [ "$1" ]; do case $1 in −h|−−help) Uso;; −V|−−version) echo $0 versão 0.1;; −m|−−message) [ "$2" ] || FaltaArg $1 ; echo "$2"; shift;; *) echo ERRO: Opção desconhecida $1;; esac shift done

O pipe no case indica as alternativas, que podem ser tantas quantas se precise. Note que a função Uso()também foi atualizada para as novas opções.

Os Segredos do Programador Shell

Fora as recomendações já vistas sobre código limpo e comentado, e sobre o uso e nomeação de variáveis efunções, o bom programador Shell segue outras dicas preciosas:

Evite o bashSempre que possível, faça seu programa compatível com o Bourne Shell (sh), para que ele funcioneno maior número de máquinas possíveis. Só use as características exclusivas do bash casonecessário. Na dúvida, use #!/bin/sh no início e certifique−se que você possui o sh em suamáquina, e não um link para o bash. A mesma dica vale pra outros Shells.

Evite o bash2Se usar bash, faça o possível para não utilizar as funcionalidades exclusivas do bash2. Muitas

AULA 3 − Explorando as Possibilidades do Shell

33 Dono: Flávio Cunha

Page 38: Apostila Shell Flavio

máquinas ainda usam o bash antigo e seu programa simplesmente não vai funcionar nelas. Cheque aversão de seu bash na variável $BASH_VERSION.

Evite o evalO eval é um comando útil, porém muito perigoso. A abstração do segundo processamento na mesmalinha pode confundir e causar perdas ou erros difíceis de detectar. Geralmente seu uso não énecessário, podendo−se fazer a mesma tarefa sem utilizá−lo.

Prefira && ao IFAo fazer um IF que não precisará de ELSE, troque−o pela estrutura [ condição ] && {comandos ; } que é mais curta e torna o código mais legível. O mesmo para IFs de condiçãonegada, que podem ser trocados por [ condição ] || { comandos ; }.

Prefira o $(...) ao `...`Para programas que precisam funcionar no sh, a subshell tem que ser com crases. Do contrário,sempre prefira o formato com chaves, pois além de ser visualmente mais fácil de perceber, é possívelaninhar subcomandos, assim: var=$(cat $(basename $arquivo)).

Evite o uso inútil do lsNão faça for i in $(ls *.txt). Isso é exatamente o mesmo que for i in *.txt, pois opróprio Shell sabe expandir asteriscos nos nomes de arquivo.

Evite o uso inútil do catNão faça cat arquivo | comando quando o próprio comando aceita receber um arquivo comoparâmetro, assim: comando arquivo.

Evite a pegadinha do whileAo invés de cat arquivo | while read LINHA; do ... done, use o redirecionamento,assim: while read LINHA; do ...done < arquivo. Assim as variáveis definidas dentro dowhile valerão para o resto do programa, o que não acontece quando se usa o cat | while.

Cuidado com o IFSA variável especial IFS pode ser um amigo ou uma pedra no sapato. Muito cuidado ao alterar seuvalor pois isso afeta o funcionamento interno do Shell. Para prevenir, guarde uma variável o valororiginal do IFS e depois restaure−o, assim: IFSOK=$IFS ; IFS=: ; comandos ; IFS=$IFSOK.No bash, basta fazer unset IFS para a variável voltar a seu valor padrão.

Faça uso racional das ferramentasO cut tem 10% do tamanho do awk. Você realmente precisa usar o awk? Será que o cut não faria amesma tarefa? Ou o sed? Ao invés de usar o perl, que tal tentar antes com o sed ou awk?

Faça uso minimalista das ferramentasFora o Shell, quantas ferramentas externas seu programa está utilizando? Os lugares onde ele seráexecutado terão todas estas ferramentas? Se sim, a versão delas será compatível com a que vocêutilizou? Será que algumas ferramentas não podem ser trocadas por outras mais comuns ou atémesmo por estruturas do próprio Shell?

Dicas Finais sobre Manutenção e Versionamento

Versionamento

Embora haja algumas tentativas de padronização, na prática, cada programador escolhe a forma denumerar/nomear versões que mais lhe agrada.

Alguns exemplos:

Versão Descrição

1 seqüencial: 1, 2, 3, 4...

1.0 seqüencial com subversões 1.1, 1.2, 1.3...

1.0.0 seqüencial com subsubversões 1.1.1, 1.1.2, ...

1.0a seqüencial com números e letras

1.0−jose seqüencial com o nome do autor

1.0−ALPHA seqüencial ALPHA (instável, primeira tentativa)

1.0−BETA1 seqüencial BETA (para pré−lançamento e testes)

AULA 3 − Explorando as Possibilidades do Shell

34 Dono: Flávio Cunha

Page 39: Apostila Shell Flavio

1.0 (mickey) seqüencial com codinome (geralmente um nome estranho)

20030131 data

3.0131 data em outros formatos

1.0−20030131 seqüencial e data

... ...

E a lista segue, numa infinidade de combinações e significados. O mais comum é o formato N.N, onde se temuma versão principal, como 2.0 e as próximas são subversões como 2.1 e 2.2. Costuma−se chamar de"série" cada conjunto de versões com uma mesma versão principal, nesse caso, seria a "série 2.x".Geralmente neste esquema, as versões ponto−zero trazem grandes novidades ou são reescritas completasda série anterior, podendo até quebrar compatibilidade.

Como regra geral, este formato N.N serve para a grande maioria dos programas e é fácil de memorizar. Casoo programa seja de atualização constante, como uma por semana ou mais, é aconselhável usar a data comoversão, para facilitar a identificação do programa.

Ou ainda, pode−se misturar formatos, usando a data quando o programa ainda está em desenvolvimentoinicial, e depois de "usável" ele partir para o N.N.

Outro detalhe é que é após a versão 1.9 por vir a 2.0, ou a 1.10 ou a 1.9a. Isso vai depender se oprogramador teve tempo de produzir a nova "série", ou ainda precisa de mais algumas subversões pararespirar. Um exemplo disso é o Vim versão 6.0, que se atrasou, esgotou todo o alfabeto de "a" a "z", ainda nãoestava pronto, e teve que usar "aa", "ab", "ac"... :)

Histórico de Mudanças: ChangeLog e NEWS

Assim como acontece com a versão, o histórico das mudanças que um programa sofreu pode ser escrito emvários formatos e seu conteúdo pode variar desde descrições extremamente técnicas, se aproximando de um"diff", até textos corridos no formato de anúncio para massas.

Há dois arquivos de nomes padrão que a maioria dos programadores utiliza:

ChangeLogUsado para registrar todas as mudanças ocorridas nos arquivos do programa, em linguagem técnica edetalhada. A audiência esperada para este arquivo são outros programadores à procura deinformações sobre o código. Caso o programa seja composto por apenas um arquivo, o histórico podeestar embutido no próprio cabeçalho, não precisando de um arquivo separado.

Exemplo:

2003−01−31 (josé): $ARQUIVO agora pode ser um link simbólico 2003−02−04 (maria): adicionada opção −−help 2003−02−05 (maria): adicionadas opções −h, −V e −−version 2003−02−06 (josé): Checagem(): adicionado aviso em $USER == 'root' 2003−02−08 (paulo): Corrigidos bugs #498, #367 e #421 2003−02−10 −−− lançada versão 1.3

NEWSUsado para registrar todas as mudanças ocorridas no programa como um todo, desde a últimaversão. A audiência esperada para este arquivo são usuários que querem saber um resumo de "quaissão as novidades". A linguagem deve ser acessível e se preciso, didática.

Exemplo:

Novidades da versão 1.3:

− Novas opções de linha de comando −h e −−help, que mostram uma tela de ajuda e também e −V e −−version, que mostram a versão do programa.

− Adicionado suporte a arquivos que são links simbólicos.

AULA 3 − Explorando as Possibilidades do Shell

35 Dono: Flávio Cunha

Page 40: Apostila Shell Flavio

− Vários bugs reportados pelos usuários foram corrigidos, como o problema da acentuação no nome do arquivo e extensão em letras maiúsculas como .TXT.

No ChangeLog, várias informações são importantes como a data da alteração, quem fez, o quê fez e porquefez. O lançamento de uma versão é apenas uma marcação cronológica, não influindo nas alterações. Caso aequipe utilize uma ferramenta de gerenciamento de problemas como o bugzilla, basta informar o número doticket.

Já no NEWS, tudo gira em torno das versões. As mudanças são agrupadas por versões e não importa quemas fez ou quando fez. Algumas mudanças podem até ser omitidas, pois somente as mudanças perceptíveispelo usuário são importantes.

Em resumo

Arquivo ChangeLog Arquivo NEWS

Lido por programadores Lido por usuários

Linguagem técnica Linguagem acessível

Agrupado por data Agrupado por versão

Quem, fez o quê, quando Mudanças desde a última versão

Frases curtas, diretas Texto normal, com exemplos e dicas

Agradecimentos a Quem Merece

Um detalhe facilmente esquecido por programadores, mas vital para que as contribuições de usuáriosaconteçam, são os agradecimentos.

Quando um usuário contribui, indicando um problema ou até mesmo mandando código pronto para seraplicado, ele faz por vontade própria, pois geralmente não há remuneração para contribuições em programas.

Pode ser um colega de trabalho, um amigo ou um usuário do outro lado do mundo que baixou seu programapela Internet, cada um deles vai ficar feliz ao ver seu nome registrado em algum arquivo ou canto do seuprograma. Isso o motivará a continuar contribuindo e seu programa continuará melhorando, com mais cabeçaspensando nele.

Não precisa ser um anúncio em letras piscantes, mas dê um jeito de agradecer e recompensar o trabalhoalheio. Todos ganham.

AULA 3 − Explorando as Possibilidades do Shell

36 Dono: Flávio Cunha

Page 41: Apostila Shell Flavio

AULA 4 − A Caixa de Ferramentas

As Ferramentas do Sistema

Assim como um bom mecânico, o programador Shell deve ter uma caixa de ferramentas recheada, que lheacompanha em toda a jornada de trabalho. É muito importante conhecer os detalhes de cada ferramenta,sabendo como usar, quando usar e também quando não usar.

Como na oficina, a escolha da ferramenta certa pode ser a diferença entre um trabalho tranqüilo e rápido, ouum festival de gambiarras que leva horas para ficar pronto e que no final nem o próprio "autor" vai ficarorgulhoso do serviço.

Já tentou soltar uma porca com um alicate de bico?• Ou apertar um parafuso com uma faca de cozinha (de ponta)?• Ou martelar um prego com uma pedra?• Ou medir paredes com régua escolar de 30cm?• Ou furar a parede com um saca−rolhas?• Ou...•

Olha, até dá pra fazer. Mas só quem já enfrentou essas situações de precariedade sabe o sacrifício que éfazer algo simples quando não se tem a ferramenta correta nas mãos.

Em Shell é exatamente o mesmo. É primordial conhecer as ferramentas e saber como utilizá−las.

Só tem um detalhe. Ao invés de uma caixa de ferramentas, o Shell é como se fosse uma loja de materiais deconstrução, com todos os tipos de ferramentas, materiais e acessórios. É um mundo de comandos, opções eparâmetros. Para todo tipo de tarefa há um programinha especialista.

Cabe a cada profissional, avaliar quais são as suas necessidades e compor a sua própria caixa deferramentas. De nada adianta uma serra tico−tico a um encanador, assim como fita veda−rosca não tem nadaa ver com marcenaria. Tanto o marceneiro quanto o encanador têm suas caixas de ferramentas, mas oconteúdo de ambas é completamente diferente.

Da mesma maneira, os programadores Shell também podem seguir rumos diferentes, se especializar emáreas distintas e serem conhecedores de ferramentas completamente diferentes.

O programador Shell deve sobretudo ter uma visão geral de quais são as ferramentas disponíveis, paraquando precisar, saber por onde começar a procurar. Além desse conhecimento geral, o programador deveser especialista nas ferramentas básicas, aquelas que independente da área estão sempre presentes nosScripts e Programas.

Esta aula apresentará estas ferramentas básicas e suas opções mais comuns, aqueles comandos que sãousados em praticamente 90% dos códigos. Para os 10% restantes, o −−help, a página de manual ou o Googleterá a resposta.

Novamente: só serão vistas as principais opções dos comandos mais importantes. Esta aula não será umalistagem sem sal de todas as opções de todos os comandos. Para isso existem as fabulosas "man pages".

Você tem todos os tamanhos de chaves de boca em sua caixa de ferramentas na garagem? Algum diaprecisou da chave número 2, 3, 25 ou 40? Que nada! Tendo uma 8, 11 e 13 já dá pra fazer muita coisa...

37 Dono: Flávio Cunha

Page 42: Apostila Shell Flavio

Abrindo a Caixa de Ferramentas

Vamos abrir nossa caixa de ferramentas e ver quais são as "armas" disponíveis para matar problemas. Cadaferramenta será vista com detalhes na próxima seção.

Comando Função Opções úteis

cat Mostra arquivo −n, −s

cut Extrai campo −d −f, −c

date Mostra data −d, +'...'

diff Compara arquivos −u, −Nr, −i, −w

echo Mostra texto −e, −n

find Encontra arquivos −name, −iname, −type f, −exec, −or

fmt Formata parágrafo −w, −u

grep Encontra texto −i, −v, −r, −qs, −n, −l, −w −x, −A −B −C

head Mostra Início −n, −c

od Mostra Caracteres −a, −c, −o, −x

paste Paraleliza arquivos −d, −s

printf Mostra texto nenhuma

rev Inverte texto nenhuma

sed Edita texto −n, −f, s/isso/aquilo/, p, d, q, N

seq Conta Números −s, −f

sort Ordena texto −n, −f, −r, −k −t, −o

tac Inverte arquivo nenhuma

tail Mostra Final −n, −c, −f

tee Arquiva fluxo −a

tr Transforma texto −d, −s, A−Z a−z

uniq Remove duplicatas −i, −d, −u

wc Conta Letras −c, −w, −l, −L

xargs Gerencia argumentos −n, −i

Analisando Cada Ferramenta

Aqui começa o "tour" pelas ferramentas e suas opções mais comuns. Sempre que preciso, volte a essa seçãopara tirar dúvidas e ver exemplos funcionais de cada comando.

Nota: Muitos dos exemplos utilizam um mesmo arquivo texto chamado numeros.txt. Este é seu conteúdo:

um dois três quatro cinco

cat

Mostra o conteúdo de um ou mais arquivos.

AULA 4 − A Caixa de Ferramentas

38 Dono: Flávio Cunha

Page 43: Apostila Shell Flavio

−n Number Numera as linhas (Formato: Espaços, Número, TAB, Linha)

−s Squeeze Remove as linhas em branco excedentes

Exemplos

$ echo −e "um\ndois\n\n\n\ntrês" um dois

três

$ echo −e "um\ndois\n\n\n\ntrês" | cat −n − 1 um 2 dois 3 4 5 6 três

$ echo −e "um\ndois\n\n\n\ntrês" | cat −n −s − 1 um 2 dois 3 4 três

Dicas

Útil para "emendar" dois arquivos:

$ cat arquivo1.txt arquivo2.txt > arquivao.txt

Geralmente "cat arquivo | comando" pode ser escrito diretamente como "comando arquivo" ou "comando <arquivo".

−o−

cut

Extrai campos ou trechos de uma linha. Possui um formato bem flexível de especificação de campos ecaracteres.

−d Delimiter Escolhe o delimitador (o padrão é o TAB)

−f Field Mostra estes campos

−c Chars Mostra estes caracteres

Maneiras de Especificar Campos/Caracteres

Formato Abrange Significa

2,5 2 5 o segundo e o quinto

2−5 2 3 4 5 do segundo ao quinto

2− 2 3 4 5 ... do segundo em diante

−5 1 2 3 4 5 até o quinto

2,5− 2 5 6 7 ... o segundo, e do quinto em diante

2,3,5−8 2 3 5 6 7 8 o segundo, o terceiro, e do quinto ao oitavo

AULA 4 − A Caixa de Ferramentas

39 Dono: Flávio Cunha

Page 44: Apostila Shell Flavio

Exemplos

$ echo 'um:dois:três:quatro:cinco' | cut −d: −f 2,3,4 dois:três:quatro

$ echo 'um:dois:três:quatro:cinco' | cut −d: −f 2−4 dois:três:quatro

$ echo 'um:dois:três:quatro:cinco' | cut −d: −f 2− dois:três:quatro:cinco

$ echo 'um:dois:três:quatro:cinco' | cut −c 4−9 dois:t

$ echo 'um:dois:três:quatro:cinco' | cut −c −10 um:dois:tr

Dicas

Útil para extrair campos de arquivos como o /etc/passwd e o /etc/fstab

$ cat fstab | tr −s ' ' | cut −d' ' −f2 swap / /mnt/cdrom /mnt/floppy /proc /dev/pts

Combine o cut com o rev para obter o(s) último(s) caracteres ou campos

$ echo 'um:dois:três:quatro:cinco' | rev | cut −d: −f1 | rev cinco

−o−

date

Mostra uma data. Possui várias opções de formatação dessa data. Caso não informada a data desejada, usaa atual.

−d Date Especifica a data (Ex.: tomorrow, 2 days ago, 5 weeks)

+%? Format Formato da data − veja tabela seguinte (Ex.: %Y−%m−%d)

Caracteres de Formatação (mais em "man date")

Formato Descrição

%a nome do dia da semana abreviado (Dom..Sáb)

%A nome do dia da semana (Domingo..Sábado)

%b nome do mês abreviado (Jan..Dez)

%B nome do mês (Janeiro..Dezembro)

%c data completa (Sat Nov 04 12:02:33 EST 1989)

%y ano (00..99)

%Y ano (1970...)

%m mês (01..12)

%d dia (01..31)

AULA 4 − A Caixa de Ferramentas

40 Dono: Flávio Cunha

Page 45: Apostila Shell Flavio

%j dia do ano (001..366)

%H horas (00..23)

%M minutos (00..59)

%S segundos (00..60)

%s segundos desde 1º de Janeiro de 1970

%% um % literal

%t um TAB

%n uma quebra de linha

Exemplos

$ date Sun Jul 20 20:29:57 2003

$ date −d yesterday Sat Jul 19 20:30:02 2003

$ date −d '4 weeks ago' Sun Jun 22 20:30:09 2003

$ date −d '123 days' +'Daqui 123 dias será %d de %b.' Daqui 123 dias será 20 de Nov.

Dicas

O formato %Y−%m−%d é bom para nomear becapes diários:

$ date +'becape−%Y−%m−%d.tgz' becape−2003−07−20.tgz

O formatador %s é útil para fazer contas com datas:

$ date +%s ; sleep 10 ; date +%s 1058733386 1058733396

$ expr 1058733396 − 1058733386 10

−o−

diff

Mostra as diferenças entre dois arquivos.

−u Unified Formato unificado (com os sinais de + e − e contexto)

−r Recusive Varre todo o diretório

−N New file Considera arquivos não encontrados como vazios

−i Ignore case Ignora a diferença entre maiúsculas e minúsculas

−w White space Ignora a diferença de linhas e espaços em branco

Exemplos

$ echo −e 'um\ndois\ntrês\nquatro' > arq1

$ echo −e 'um\ntrês\nquatro\ncinco' > arq2

AULA 4 − A Caixa de Ferramentas

41 Dono: Flávio Cunha

Page 46: Apostila Shell Flavio

$ diff −u arq1 arq2 −−− arq1 Sun Jul 20 20:56:28 2003 +++ arq2 Sun Jul 20 20:57:36 2003 @@ −1,4 +1,4 @@ um −dois três quatro +cinco

$ echo −e 'um\ndoisss\ntrêsss\nquatro' > arq3

$ diff −u arq1 arq3 −−− arq1 Sun Jul 20 20:56:28 2003 +++ arq3 Sun Jul 20 20:57:56 2003 @@ −1,4 +1,4 @@ um −dois −três +doisss +trêsss quatro

Dicas

Use as opções −Nur para comparar dois diretórios

$ diff −Nur dir1 dir2

Passe um número para o −u para definir quantas linhas de contexto:

$ diff −u0 arq1 arq2 −−− arq1 Sun Jul 20 20:56:28 2003 +++ arq2 Sun Jul 20 20:57:36 2003 @@ −2 +1,0 @@ −dois @@ −4,0 +4 @@ +cinco

O resultado é um arquivo pronto para ser usado pelo comando patch:

$ diff −u arq2 arq3 > alteracoes.patch

$ patch arq2 < alteracoes.patch patching file `arq2'

$ diff arq2 arq3

$

Para ver a saída colorida, use o vi:

$ diff −u arq1 arq3 | vi −

−o−

echo

Mostra um texto. Útil para ecoar mensagens na tela.

−n Newline Não quebra a linha no final

−e Escape Interpreta os escapes especiais (ver tabela)

AULA 4 − A Caixa de Ferramentas

42 Dono: Flávio Cunha

Page 47: Apostila Shell Flavio

Escapes reconhecidos pelo echo

Escape Mnemônico Descrição

\a Alert Alerta (bipe)

\b Backspace Caractere Backspace

\c EOS Termina a string

\e Escape Caractere Esc

\f Form feed Alimentação

\n Newline Linha nova

\r Return Retorno de carro

\t Tab Tabulação horizontal

\v Vtab Tabulação vertical

\\ Backslash Barra invertida \ literal

\nnn Octal Caractere cujo octal é nnn

\xnn Hexa Caractere cujo hexadecimal é nn

Exemplos

$ echo −e '0\t1\t2\t3\t4\t5\t6\t7' 0 1 2 3 4 5 6 7

$ echo −e 'Bip!\a Bip!\a Bip!\a' Bip! Bip! Bip!

$ echo −e '\x65\x63\x68\x6F\x21' echo!

Dicas

Em algumas versões do echo, o −e não é necessário.

Para maior controle de alinhamento e formatação, use o printf.

Com um pouco de criatividade, usando os escapes \b e \r pode−se fazer pequenas "animações" no console,como uma barra de progresso que mostra a porcentagem:

$ echo −n '[ 33%]'; sleep 1 ; echo −ne '\r[ 66' ; \ sleep 1 ; echo −e '\b\b\b100' [100%]

Ou a hélice ASCII:

while :; do for a in / − \\ \|; do echo −ne "\b$a"; done; done

−o−

find

Encontra arquivos procurando pelo nome, data, tamanho e outras propriedades.

−name Especifica o nome do arquivo (ou *parte* dele)

−iname Ignora a diferença entre maiúsculas e minúsculas no nome

AULA 4 − A Caixa de Ferramentas

43 Dono: Flávio Cunha

Page 48: Apostila Shell Flavio

−type Especifica o tipo do arquivo (f=arquivo, d=diretório, l=link)

−mtime Mostra os arquivos modificados há N dias

−size Mostra os arquivos que possuem o tamanho especificado

−user Mostra os arquivos de um usuário específico

−ls Mostra os arquivos no mesmo formato do comando ls

−printf Formatação avançada para mostrar os nomes dos arquivos

−exec Executa um comando com os arquivos encontrados

−ok Executa um comando com os arquivos encontrados, com confirmação

−and, −or E, OU lógico para as condições

−not Inverte a lógica da expressão

Detalhes das opções −exec e −ok

A string "{}" representa o nome do arquivo encontrado1. O comando deve ser passado sem aspas2. O comando deve ser terminado por um ponto−e−vírgula escapado \;3. Tem que ter um espaço antes do ponto−e−vírgula escapado4. Por exemplo, para mover todos os arquivos ".txt" para ".txt.old":

$ find . −name '*.txt' −exec mv {} {}.old \;

5.

Exemplos

$ find /etc −iname 'x*' /etc/X11 /etc/xinetd.d /etc/log.d/conf/logfiles/xferlog.conf /etc/log.d/scripts/logfiles/xferlog

$ find /etc −iname 'x*' −maxdepth 1 /etc/X11 /etc/xinetd.d

$ find /etc −type d −name 'cron*' −and −not −name 'cron.d*' /etc/cron.hourly /etc/cron.monthly /etc/cron.weekly

Dicas

Releia os detalhes das opções −exec e −ok, você vai precisar.

Para procurar mais de um tipo de arquivo:

$ find . −name '*.txt' −or −name '*.html'

Para apagar todos os arquivos .mp3 de um diretório, incluindo subdiretórios:

$ find . −iname '*.mp3' −exec rm −f {} \;

Para encontrar todos os links simbólicos do diretório atual, e mostrar para onde eles apontam:

$ find . −type l −ls | cut −d/ −f2−

−o−

AULA 4 − A Caixa de Ferramentas

44 Dono: Flávio Cunha

Page 49: Apostila Shell Flavio

fmt

Formatador simples de parágrafos. Adiciona ou remove quebras de linha e espaços para que o texto nãoultrapasse o número máximo de colunas.

−w Width Define o número máximo de colunas (o padrão é 75)

−u Uniform Remove espaços excedentes

Exemplos

$ cat fmt.txt Hello! This is Linus Torvalds and I pronounce Linux as Linux.

$ cat fmt.txt | fmt −w35 Hello! This is Linus Torvalds and I pronounce Linux as Linux.

$ cat fmt.txt | fmt −w35 −u Hello! This is Linus Torvalds and I pronounce Linux as Linux.

Dicas

O fmt é similar ao comando "gq" do vi

grep, egrep e fgrep

Procura em arquivos ou textos por linhas que contêm determinado padrão de pesquisa. O padrão pode seruma string ou uma Expressão Regular.

−i Ignore case Ignora a diferença entre maiúsculas e minúsculas

−v inVert Mostra as linhas que não casam com o padrão

−r Recursive Varre subdiretórios também

−qs Quiet Não mostra as linhas nem erros (usar com o test)

−n line Number Mostra também o número da linha

−c Count Conta o número de linhas encontradas

−l − Mostra apenas o nome o arquivo que casou

−w Word O padrão é uma palavra inteira e não parte dela

−x − O padrão é uma linha inteira e não parte dela

−A After Mostre N linhas de contexto depois do padrão

−B Before Mostre N linhas de contexto antes do padrão

−C Context Mostre N linhas de contexto antes e depois do padrão

As identidades do grep

Comando O padrão de pesquisa é...

grep Uma string ou Expressão Regular básica

egrep ou "grep −E" Uma Expressão Regular estendida

fgrep ou "grep −F" Uma string

AULA 4 − A Caixa de Ferramentas

45 Dono: Flávio Cunha

Page 50: Apostila Shell Flavio

Os Metacaracteres

Expressão Regular básica ^ $ . * [ \? \+ \| \( \) \{ \}

Expressão Regular estendida ^ $ . * [ ? + | ( ) { }

Exemplos

$ seq 10 | grep −A1 −B3 7 4 5 6 7 8

$ cat grep.txt 1. Grep é g/re/p, que é Global Regular Expression Print. 2. Com o *grep na mão, nenhum dado está perdido. 3. Grep, Egrep e Fgrep. Uma família e tanto! 4. Não saia de casa sem o seu [fe]?grep. 5. Grep me harder!

$ cat grep.txt | fgrep grep 2. Com o *grep na mão, nenhum dado está perdido. 3. Grep, Egrep e Fgrep. Uma família e tanto! 4. Não saia de casa sem o seu [fe]?grep.

$ cat grep.txt | fgrep −w grep 2. Com o *grep na mão, nenhum dado está perdido. 4. Não saia de casa sem o seu [fe]?grep.

$ cat grep.txt | egrep −i '(grep.+){3}' 3. Grep, Egrep e Fgrep. Uma família e tanto!

$ cat grep.txt | grep −i '\(grep.\+\)\{3\}' 3. Grep, Egrep e Fgrep. Uma família e tanto!

Dicas

Sempre que possível use o fgrep, pois ele é mais rápido.

A opção −l é útil para corrigir um mesmo erro em vários arquivos:

vi $(grep −l 'emossão' *.txt)

Note que o −c conta as linhas e não as palavras:

$ echo 'grep, grep, grep, grep' | grep −c grep 1

As opções −qs são usadas em testes e condicionais:

$ if grep −qs 'grep' grep.txt ; then echo achei ; fi achei

$ grep −qs 'grep' grep.txt && echo achei achei

Nenhum programador Shell sobrevive sem o grep. Domine−o!

−o−

head

Mostra o início de um texto. A quantidade a ser mostrada pode ser expressa em linhas ou caracteres. Seuirmão é o tail.

AULA 4 − A Caixa de Ferramentas

46 Dono: Flávio Cunha

Page 51: Apostila Shell Flavio

−n liNes Mostra as N primeiras linhas (o padrão é 10)

−c Char Mostra os N primeiros caracteres (incluindo \n)

Exemplos

$ head −n 3 numeros.txt um dois três

$ head −c 8 numeros.txt um dois

Dicas

A letra 'n' pode ser omitida da opção, especificando−se diretamente o número de linhas desejadas:

head −3 numeros.txt

−o−

od

O od é o Octal Dump, que serve para mostrar o código de cada caractere de um arquivo ou texto. Além deoctal, também mostra os códigos em hexadecimal e ASCII.

−a nAmed char Mostra os nomes dos caracteres

−c ASCII Char Mostra os caracteres ASCII ou \?

−o Octal Mostra os códigos em octal

−x heXadecimal Mostra os códigos em hexadecimal

Exemplos

$ echo od, que legal | od −h 0000000 646f 202c 7571 2065 656c 6167 0a6c 0000016

$ echo od, que legal | od −c 0000000 o d , q u e l e g a l \n 0000016

$ echo −ne '\a\b\f\n\r\t\v' | od −ac 0000000 bel bs ff nl cr ht vt \a \b \f \n \r \t \v 0000007

Dicas

O od é especialmente útil para visualizar espaços em branco. Por exemplo, quantos espaços existem entreessas duas palavras?

quantos brancos?

Ao usar o od, vemos que há algo mais além de espaços:

$ echo "quantos brancos?" | od −a 0000000 q u a n t o s sp sp sp ht sp b r a n 0000020 c o s ? nl 0000025

AULA 4 − A Caixa de Ferramentas

47 Dono: Flávio Cunha

Page 52: Apostila Shell Flavio

São 3 espaços, um TAB e outro espaço.

−o−

paste

Junta linhas de vários arquivos em um só. Ele coloca as linhas lado a lado, uma por uma, como se colocasseos arquivos em paralelo. Cada arquivo vira uma "coluna" do resultado. Com a opção −s o resultado éinvertido, e cada arquivo vira uma "linha".

−d Delimiter Escolhe o delimitador (o padrão é o TAB)

−s Serial Transforma todas as linhas em apenas uma

Exemplos

$ cat numeros.txt um dois três quatro cinco

$ cat numbers.txt one two three four five

$ paste numeros.txt numbers.txt um one dois two três three quatro four cinco five

$ paste −s numeros.txt numbers.txt um dois três quatro cinco one two three four five

$ paste −d: numeros.txt numbers.txt um:one dois:two três:three quatro:four cinco:five

Dicas

Mais de dois arquivos podem ser passados, inclusive o mesmo arquivo mais de uma vez:

$ paste numeros.txt numbers.txt numeros.txt numbers.txt numeros.txt um one um one um dois two dois two dois três three três three três quatro four quatro four quatro cinco five cinco five cinco

Com apenas um arquivo, a opção −s é útil para transformar linhas em colunas, com o delimitador a escolher:

$ paste −d: −s numeros.txt um:dois:três:quatro:cinco

AULA 4 − A Caixa de Ferramentas

48 Dono: Flávio Cunha

Page 53: Apostila Shell Flavio

printf

Mostra um texto usando vários formatadores especiais. Todos os escapes usados pelo comando echo (como\t e \n) também são válidos no printf.

Formatadores do comando printf

Formato Descrição

%d Número decimal

%o Número octal

%x Número hexadecimal (a−f)

%X Número hexadecimal (A−F)

%f Número com ponto flutuante

%e Número em notação científica (e+1)

%E Número em notação científica (E+1)

%s String

Exemplos

$ printf '%o \n' 10 12

$ printf '%X \n' 10 A

$ printf '%f \n' 10 10.000000

$ printf '%.3f \n' 10 10.000

$ printf '%.3e \n' 10 1.000e+01

$ printf '(%15s) \n' direita ( direita)

$ printf '(%−15s) \n' esquerda (esquerda )

Dicas

Diferente do echo, o printf não quebra a linha no final da string. Deve−se colocar um \n no final para obteresse efeito.

As opções de alinhamento do %s são muito boas para compor relatórios:

$ z=15; printf "%${z}s:\n%${z}s:\n%${z}s:\n" 'Nome Completo' Idade Sexo Nome Completo: Idade: Sexo:

−o−

rev

Inverte a ordem dos caracteres da linha, colocando−os de trás para frente. Funciona como um espelho onde'texto' vira 'otxet'. Seu primo que inverte linhas é o tac.

AULA 4 − A Caixa de Ferramentas

49 Dono: Flávio Cunha

Page 54: Apostila Shell Flavio

Exemplos

$ echo O rev é muito bacana. | rev .anacab otium é ver O

$ echo O rev é muito bacana. | rev | rev O rev é muito bacana.

Dicas

Usando o cut sozinho, não há como especificar o último campo, ou o último caractere. Com o rev, isso épossível:

$ echo 123456789 | rev | cut −c1 9

Similarmente, para pegar os 5 últimos caracteres:

$ echo 123456789 | rev | cut −c1−5 | rev 56789

−o−

sed

Editor de textos não interativo e programável. Executa uma série de comandos de edição em um texto. Seuuso clássico é trocar uma string por outra, assim: s/isso/aquilo/. Esse comando significa: troque 'isso' por'aquilo'.

−n Not Print Só mostra a linha caso usado o comando p

−e Expression Especifica os comandos de edição

−f File Lê os comandos de edição de um arquivo

Comandos do sed

Comando Mnemônico Ação

s/// Substitute Troca um texto por outro

p Print Mostra a linha na saída

l List Mostra a linha na saída, com \t, \a, ...

d Delete Apaga a linha

q Quit Sai do sed

r Read Lê o conteúdo de um arquivo

N Next line Junta a próxima linha com a atual

Endereços de comandos

Endereço Abrange...

1 A primeira linha

1,5 Da primeira linha até a quinta

5,$ Da quinta linha até a última

/sed/ A(s) linha(s) que contém a palavra "sed"

AULA 4 − A Caixa de Ferramentas

50 Dono: Flávio Cunha

Page 55: Apostila Shell Flavio

5,/sed/ Da quinta linha até a linha que contém "sed"

/sed/,/grep/ Da linha que contém "sed" até a que contém "grep"

1,5! Todas as linhas exceto da primeira a quinta

/sed/! A(s) linha(s) que não contém a palavra "sed"

Detalhes do comando s///

Char Exemplo Descrição

g s/a/b/g Modificador Global, para trocar todas as ocorrências

p s/a/b/gp Modificador Print, para mostrar o texto substituído

& s/./& / Expande para todo o trecho casado na primeira parte

\1 s/\(.\)/\1 / Expande para o conteúdo do primeiro grupo marcado com \(...\)

Exemplos

$ cat numeros.txt | sed '1,3d' quatro cinco

$ cat numeros.txt | sed '/o$/d' um dois três

$ cat numeros.txt | sed '/dois/q' um dois

$ echo um dois três quatro cinco | sed 's/ //g' umdoistrêsquatrocinco

$ cat numeros.txt | sed 's/tr/_TR_/ ; s/^/− /' − um − dois − _TR_ês − qua_TR_o − cinco

Dicas

O sed usa os mesmos metacaracteres básicos do grep

O comando l é útil para decifrar espaços em branco:

$ echo −e '\t\t\a ' | sed −n l \t\t\a $

Pode−se usar outro delimitador no comando s/// para evitar confusão:

$ echo /usr/bin/sed | sed 's,/usr/bin,/tmp,' /tmp/sed

Algumas versões do sed reconhecem os mesmo escapes do comando echo:

$ echo um dois três quatro cinco | sed 's/ /\t/g' um dois três quatro cinco

O comando p pode ser usado para mostrar a linha antes de editá−la:

AULA 4 − A Caixa de Ferramentas

51 Dono: Flávio Cunha

Page 56: Apostila Shell Flavio

$ cat numeros.txt | sed 'p ; s/./& /g ; s/^/−−−> /' um −−−> u m dois −−−> d o i s três −−−> t r ê s quatro −−−> q u a t r o cinco −−−> c i n c o

−o−

seq

Dados dois números, faz a contagem de um até o outro. A contagem pode ser crescente ou decrescente,dependendo de qual dos dois números é o maior. Se o primeiro número for omitido, o 1 é usado.

−s Separator Define o separador (o padrão é \n)

−f Format Define o formato do número (o padrão é %g)

Exemplos

$ seq 4 1 2 3 4

$ seq 2 5 2 3 4 5

$ seq 2 −2 2 1 0 −1 −2

$ seq −s, 20 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20

$ seq −s'...' −f'%04g' 7 0001...0002...0003...0004...0005...0006...0007

Dicas

O seq é útil para usar junto com o for:

for i in $(seq 10); do echo Contando: $i; done

−o−

sort

Ordena as linhas de um texto, alfabética ou numericamente.

−n Numeric Ordena numericamente (o padrão é alfabeticamente)

−r Reverse Reverte a ordenação (de Z para A, de 9 para 0)

AULA 4 − A Caixa de Ferramentas

52 Dono: Flávio Cunha

Page 57: Apostila Shell Flavio

−f Ignore case Ignora a diferença entre maiúsculas e minúsculas

−k Key Ordena pela coluna N (a primeira é 1)

−t separaTor Escolhe o delimitador para o −k (o padrão é o TAB)

−o Output Grava a saída no arquivo especificado

Exemplos

$ sort numeros.txt cinco dois quatro três um

$ cat −n numeros.txt | sort −k2 5 cinco 2 dois 4 quatro 3 três 1 um

$ echo −e "1\n10\n100\n2\n20\n200" | sort 1 10 100 2 20 200

$ echo −e "1\n10\n100\n2\n20\n200" | sort −n 1 2 10 20 100 200

Dicas

Usando a opção −o é possível ordenar um arquivo e gravar o resultado nele mesmo:

$ sort arquivo.txt −o arquivo.txt

−o−

tac

tac é o contrário de cat. Mostra o texto ao contrário, da última para a primeira linha. O que o rev faz comcaracteres, o tac faz com linhas.

Exemplos

$ cat numeros.txt um dois três quatro cinco

$ tac numeros.txt cinco quatro três dois um

AULA 4 − A Caixa de Ferramentas

53 Dono: Flávio Cunha

Page 58: Apostila Shell Flavio

Dicas

O tac é útil para se usar em conjunto com o sed, grep, awk ou outros processadores orientados à linha,quando se precisa procurar ou mostrar registros em ordem reversa.

−o−

tail

Mostra o final de um texto. A quantidade a ser mostrada pode ser expressa em linhas ou caracteres. Seuirmão é o head.

−n liNes Mostra as N últimas linhas (o padrão é 10)

−c Char Mostra os N últimos caracteres (incluindo \n)

−f Follow Monitora o arquivo "ad infinitum"

Exemplos

$ tail −n 3 numeros.txt três quatro cinco

$ tail −c 8 numeros.txt o cinco

$ tail −c 8 numeros.txt | od −c 0000000 o \n c i n c o \n 0000010

Dicas

A letra 'n' pode ser omitida da opção, especificando−se diretamente o número de linhas desejadas:

tail −3 numeros.txt

A opção −f é muito útil para monitorar arquivos de log do sistema em tempo real.

tail −f /var/log/messages

−o−

tee

Salva o fluxo de dados de um pipe para um arquivo, sem interrompê−lo.

−a Append Anexa ao final do arquivo (o padrão é sobrescrever)

Exemplos

$ echo "um texto qualquer" | tee tee.txt um texto qualquer

$ cat tee.txt um texto qualquer

$ echo "um outro texto" | tee −a tee.txt um outro texto

AULA 4 − A Caixa de Ferramentas

54 Dono: Flávio Cunha

Page 59: Apostila Shell Flavio

$ cat tee.txt um texto qualquer um outro texto

Dicas

Útil para fazer depuração (debug), obtendo o estado de um fluxo num comando muito extenso.

Útil para mensagens de log, que vão para a tela e também para um arquivo.

−o−

tr

Transforma, espreme e apaga caracteres, funcionando como um filtro. Reconhece os mesmos escapes docomando echo.

−s Squeeze Espreme caracteres iguais consecutivos para apenas um

−d Delete Apaga todos os caracteres listados

Parâmetros especiais do tr

Parâmetro Engloba

abc 'a' e 'b' e 'c'

a7z 'a' e '7' e 'z'

a−z de 'a' até 'z'

0−7 de zero a sete

Exemplos

$ echo O tr é muito versátil | tr ' ' '\t' O tr é muito versátil

$ echo O tr é muito versátil | tr a−z A−Z O TR é MUITO VERSáTIL

$ echo O tr é muito versátil | tr a−zéá A−ZÉÁ O TR É MUITO VERSÁTIL

$ echo O tr é muito versátil | tr −d aeiouéá O tr mt vrstl

$ echo "muitos espaços" | tr −s ' ' muitos espaços

$ cat numeros.txt | tr '\n' , um,dois,três,quatro,cinco,

Dicas

Em sistemas com o locale corretamente configurado para o português, os seguintes parâmetros tambémenglobam caracteres acentuados:

$ echo O tr é muito versátil | tr [:lower:] [:upper:] O TR É MUITO VERSÁTIL

−o−

AULA 4 − A Caixa de Ferramentas

55 Dono: Flávio Cunha

Page 60: Apostila Shell Flavio

uniq

Remove linhas repetidas consecutivas em um texto, deixando apenas uma.

−i Ignore case Ignora a diferença entre maiúsculas e minúsculas

−d Duplicate Mostra apenas as linhas que são repetidas

−u Unique Mostra apenas as linhas que não são repetidas

Exemplos

$ cat uniq.txt um um um dois Dois DOIS três um

$ cat uniq.txt | uniq um dois Dois DOIS três um

$ cat uniq.txt | uniq −i um dois três um

$ cat uniq.txt | uniq −id um dois

$ cat uniq.txt | uniq −iu três um

Dicas

Para remover todas as linhas repetidas, mesmo que não sejam consecutivas, é preciso ordenar o textoprimeiro:

$ sort −f uniq.txt | uniq −i DOIS três um

Para fazer a mesma operação anterior, mas mantendo a mesma ordem original, é preciso engenhosidade:

$ cat −n uniq.txt | sort −f −k2 | uniq −i −f1 | sort −n | cut −f2− um dois três

−o−

wc

Conta letras, palavras e linhas em um texto.

AULA 4 − A Caixa de Ferramentas

56 Dono: Flávio Cunha

Page 61: Apostila Shell Flavio

−c Char Conta o número de caracteres (bytes)

−w Word Conta o número de palavras

−l Line Conta o número de linhas

−L Longest Mostra a tamanho da linha mais comprida

Exemplos

$ paste numeros.txt numbers.txt um one dois two três three quatro four cinco five

$ paste numeros.txt numbers.txt | wc 5 10 50

$ wc −l numeros.txt numbers.txt 5 numeros.txt 5 numbers.txt 10 total

Dicas

A opção −L é útil quando se precisa posicionar um texto na tela, pois saber o tamanho da linha mais compridaé essencial:

tamanho_max=$(wc −L < arquivo.txt)

Há diferença entre passar o nome do arquivo para o wc ou mandar o texto via STDIN. Em programas,geralmente usa−se a segunda forma, para obter apenas o número:

$ wc −l numeros.txt 5 numeros.txt

$ wc −l < numeros.txt 5

−o−

xargs

Gerenciador de argumentos da linha de comando. Executa comandos passando os argumentos recebidos viaSTDIN. O comando padrão é o echo.

−n Number Use N argumentos por linha de comando

−i replace Troca a string "{}" pelo argumento da vez

Exemplos

$ cat numeros.txt | xargs um dois três quatro cinco

$ cat numeros.txt | xargs −n 2 um dois três quatro cinco

$ cat numeros.txt | xargs −i echo Contando: {}... Contando: um... Contando: dois... Contando: três... Contando: quatro...

AULA 4 − A Caixa de Ferramentas

57 Dono: Flávio Cunha

Page 62: Apostila Shell Flavio

Contando: cinco...

Dicas

Útil para aplicar um comando para uma lista de arquivos, por exemplo, para criar cópias de todos os arquivostexto do diretório atual:

ls −1 *.txt | xargs −i cp {} {}.bak

O similar em Shell requer uso de loop:

for arq in *.txt ; do cp $arq $arq.bak ; done

Útil para evitar o uso de subshell e tratar nomes de arquivos com espaços, onde:

rm $(grep −l 'string' *.txt)

Fica:

grep −l 'string' *.txt | xargs rm

−o−

Os Caracteres de Controle

O Que São Caracteres de Controle

Desconhecidos por uns, temidos por outros, os Caracteres de Controle são peças essenciais para um sistemade computação poder posicionar e desenhar texto na tela. São eles que informam à placa de vídeo a posiçãodo cursor, além de alterarem propriedades do texto, como a cor da letra e a cor do fundo.

Por exemplo, como mostrar um texto exatamente na décima linha da tela? Ou como desenhar uma "caixa" natela colocando texto variável dentro dela? Ou ainda, como dar pulos com o cursor, reescrevendo na mesmaposição sempre para fazer uma barra de progresso? Tudo isso é feito com caracteres de controle.

Com a liberdade de movimentos que se consegue após dominar estes caracteres especiais, o limite é a suaimaginação, pois virtualmente qualquer tipo de tela com caracteres pode ser desenhada: animações, caixas,jogos, interfaces, botões...

Os Caracteres de Controle são "seqüências de escape", caracteres normais precedidos por um caractere Esc.Por exemplo, a seqüência ESC + [ + 2 + J limpa toda a tela, não importando a posição atual do cursor.

As seqüências devem ser simplesmente ecoadas na tela. Então basta usar o echo ou o printf.Experimente:

$ echo −ne '\033[2J'

O caractere Esc é obtido usando seu código octal 033 e a opção −e do echo para interpretar esse código.Também é possível ecoar um Esc literal apertando Ctrl+V, Esc, aparecerá um ^[ na tela para representar ocaractere. Mas como comandos com o Esc literal não podem ser copiados/colados, a notação 033 será autilizada.

Também foi usada a opção −n, para que o echo não quebrasse a linha no final. Ela sempre deve usada aoecoar Caracteres de Controle, pois a quebra de linha atrapalha as operações de posicionamento do cursor.Outra alternativa é usar o printf, que também não quebra a linha:

$ printf '\033[2J'

Como não precisamos das funções avançadas de formatação do printf, o echo −ne será o comando utilizadonos exemplos.

AULA 4 − A Caixa de Ferramentas

58 Dono: Flávio Cunha

Page 63: Apostila Shell Flavio

Todas as seqüências começam com um ESC seguido de um colchete, então ESC[ é o início de todas asseqüências de Caracteres de Controle que veremos.

Mostrando Cores na Tela

Para começar, nada de pulos com o cursor ou operações complicadas. A maior necessidade dosprogramadores que procuram os Caracteres de Controle é mostrar letras coloridas na tela, ou trocar a cor dofundo. A seqüência para códigos de cor tem a seguinte sintaxe:

ESC [ n1 ; n2 ; ... m

Começa com o ESC[ padrão e termina com a letra m. Entre os dois são colocados números separados porponto−e−vírgula, que indicam as cores a serem utilizadas. Caso nenhum número seja informado (ESC[m), ozero é assumido.

Códigos das Cores da Seqüência ESC[...m

Código Descrição Código Descrição

0 texto normal (sem cores) 5 pisca−pisca

1 cor brilhante 7 vídeo reverso (invertido)

30 texto preto (cinza) 40 fundo preto (cinza)

31 texto vermelho 41 fundo vermelho

32 texto verde 42 fundo verde

33 texto marrom (amarelo) 43 fundo marrom (amarelo)

34 texto azul 44 fundo azul

35 texto roxo 45 fundo roxo

36 texto ciano 46 fundo ciano

37 texto cinza (branco) 47 fundo cinza (branco)

Basta consultar esta tabela e pronto. Então, para mostrar uma mensagem com letras vermelhas na tela, basta:

$ echo −e '\033[31m MENSAGEM IMPORTANTE!!! \033[m'

A primeira seqüência é o ESC[...m usando a cor 31 (vermelho) e no final usa−se a seqüência vazia ESC[mpara voltar as cores ao normal, senão a tela continuará com cores vermelhas. Mas no fundo preto, as coresnormais ficam meio "apagadas", muito escuras. É preciso também colocar o atributo "brilhante" na primeiraseqüência, para facilitar a visualização:

$ echo −e '\033[31;1m MENSAGEM IMPORTANTE!!! \033[m'

E assim vão se adicionando os códigos desejados, separados entre si por ponto−e−vírgula. Num exemplomais elaborado, 44;31;1;5 define fundo azul com letra vermelha e brilhante, e ainda tem o código 5 queindica texto que pisca:

$ echo −e '\033[44;31;1;5m fundo azul, letra vermelha \033[m'

Obs.: O atributo de piscar não funciona em alguns tipos de terminal.

Note que a cor brilhante geralmente indica o vermelho claro, verde claro, e assim vai. As exceções são omarrom que vira amarelo, o preto que vira cinza e o cinza que vira branco.

Posicionando o Cursor

Agora que já sabemos como colorir um texto, vamos ver como colocá−lo exatamente onde queremos na tela.

AULA 4 − A Caixa de Ferramentas

59 Dono: Flávio Cunha

Page 64: Apostila Shell Flavio

O formato padrão dos comandos de movimentação é ESC[<quantidade><comando>. Vamos começar comos comandos de movimentação simples, os mais comuns:

Comandos de Movimentação do Cursor

Comando Ação (o padrão é n=1 e m=1)

ESC[nA Move o cursor n linhas para cima, na mesma coluna

ESC[nB Move o cursor n linhas para baixo, na mesma coluna

ESC[nC Move o cursor n colunas para a direita, na mesma linha

ESC[nD Move o cursor n colunas para a esquerda, na mesma linha

ESC[nE Move o cursor n linhas para baixo, na coluna 1

ESC[nF Move o cursor n linhas para cima, na coluna 1

ESC[nG Move o cursor para a coluna n da linha atual

ESC[n;mH Move o cursor para a coluna m da linha n

É fácil, basta ecoar o comando e o cursor vai dar o pulo, por exemplo, ESC[5E pula para o começo da 5ª linhaabaixo da posição atual.

Para ficar mais visual o que cada comando desses faz, aqui vai um "gráfico" de exemplo de movimentação docursor com os comandos sendo executados com seus valores padrão (n=1,m=1) à partir da posição marcadapelo ponto, que está na linha 4 coluna 7:

123456789 +−−−−−−−−−− 1|H 2| 3|F A 4|G D.C 5|E B 6|

E como um exemplo prático, este comando gera o conteúdo do gráfico anterior:

echo −e '\033c\033[HH\033[4;7H.C\033[3DD\033[AA\033[GF\nG\nE\033[7GB'

Destrinchando essa tripa:

\033c Limpa a tela. A seqüência ESCc é igual a ESC[2J já vista

\033[HH Coloca a letra H na canto superior esquerdo da tela

\033[4;7H. Pulo para a linha 4 coluna 7, a posição do ponto

C Com o cursor após o ponto, aproveita para colocar a letra C

\033[3DD Volta 3 posições à esquerda para colocar a letra D

\033[AA Com o cursor sobre o ponto, sobe uma linha e coloca a letra A

\033[GF Pula para o início da linha e coloca a letra F

\nG\nE Usa o \n para descer linhas e coloca as letras G e E

\033[7GB Finalmente pula para a coluna 7 da mesma linha e coloca a letra B

AULA 4 − A Caixa de Ferramentas

60 Dono: Flávio Cunha

Page 65: Apostila Shell Flavio

Comandos de Som

Também é possível alterar propriedades do bipe do computador (speaker) com os Caracteres de Controle. Hádois comandos de som, um para definir a duração de um bipe, e outro para definir a sua freqüência.

Comandos de Som (Speaker)

ESC[10;n] Define a freqüência para "n" (o padrão é 750)

ESC[11;n] Define a duração para "n" milisegundos (o padrão é 100)

Por exemplo, se quiser que cada bipada em sua máquina dure 2 segundos, basta fazer:

$ echo −e '\033[11;2000]'

Com criatividade e muita paciência é até possível fazer músicas com o echo. Mas isso fica como exercíciopara casa :)

Outros Comandos

Além de poder posicionar o cursor e mostrar caracteres coloridos na tela, os Caracteres de Controle aindapossuem outros comandos, que servem para:

Apagar trechos da linha ou tela• Inserir espaços ou linhas em branco• Mover a tela•

Comandos de Movimentação de Tela e Edição

Comando Ação

ESC[0J Apaga até o fim da tela

ESC[1J Apaga até o começo da tela

ESC[2J Apaga a tela toda

ESC[0K Apaga até o fim da linha

ESC[1K Apaga até o começo da linha

ESC[2K Apaga a linha toda

AULA 4 − A Caixa de Ferramentas

61 Dono: Flávio Cunha

Page 66: Apostila Shell Flavio

Comando Ação (o padrão é n=1)

ESC[nM Apaga n linhas para baixo

ESC[nP Apaga n caracteres à direita

ESC[nX Limpa n caracteres à direita (coloca espaços)

ESC[n@ Insere n espaços em branco

ESC[nL Insere n linhas em branco

ESC[nS Move a tela n linhas para cima

ESC[nT Move a tela n linhas para baixo

Antes de terminar, vale lembrar que alguns comandos como o tput ou bibliotecas como ncurses visamfacilitar a tarefa de posicionamento de texto e desenho de caixas e botões, com funções já prontas para fazerisso. Mas é mais divertido fazer na mão &;)

Exemplos

Paleta de Cores

#!/bin/sh # cores.sh − Mostra todas as combinações de cores do console # 2003−07−23 Aurelio Marinho Jargas

for letra in 0 1 2 3 4 5 6 7; do # LINHAS: cores das letras for brilho in '' ';1'; do # liga/desliga cor brilhante for fundo in 0 1 2 3 4 5 6 7; do # COLUNAS: cores dos fundos seq="4$fundo;3$letra" # compõe código de cores echo −e "\033[$seq${brilho}m\c" # liga a cor echo −e " $seq${brilho:− } \c" # mostra o código na tela echo −e "\033[m\c" # desliga a cor done; echo # quebra a linha done done

Barra de Progresso

#!/bin/bash # gauge.sh − barra de progresso usando caracteres de controle # 2003−07−23 Aurelio Marinho Jargas # # [.................................................] 0% # [########################.........................] 50% # [#################################################] 100 #

# barra vazia echo −n '[.................................................] 0%'

passo='#####'

for i in 10 20 30 40 50 60 70 80 90 100; do sleep 1 pos=$((i/2−5)) # calcula a posição atual da barra echo −ne '\033[G' # vai para o começo da linha echo −ne "\033[${pos}C" # vai para a posição atual da barra echo −n "$passo" # preenche mais um passo echo −ne '\033[53G' # vai para a posição da porcentagem echo −n "$i" # mostra a porcentagem done; echo

AULA 4 − A Caixa de Ferramentas

62 Dono: Flávio Cunha

Page 67: Apostila Shell Flavio

Teste de Som

#!/bin/bash # som.sh − demonstração de mudança da freqüência do Speaker # 2003−07−30 Aurelio Marinho Jargas

# Restaura o bipe padrão (f=750, t=100ms) echo −e '\033[10;750]\033[11;100]'

freq=0 # freqüência inicial while : ; do # loop infinito freq=$((freq+1)) # aumenta freqüência echo −e "\033[10;$freq]" # muda freq no Speaker echo "frequência=$freq" # mostra freq atual echo −e '\a' # emite um beep usleep 100 # espera 100us done

Encaixotador de Texto

#!/bin/bash # caixa.sh − Encaixota um texto qualquer vindo da STDIN # 2003−07−23 Aurelio Marinho Jargas # # Usando caracteres de controle, primeiro desenha uma caixa: # +−−−−−−−−−−+ # | | # | | # +−−−−−−−−−−+ # # Depois coloca o texto recebido via STDIN dentro dessa caixa: # +−−−−−−−−−−+ # | O texto | # | recebido | # +−−−−−−−−−−+ # # A separação do código em dois passos permite personalizar # separadamente a caixa e o texto, podendo−se facilmente # adicionar cores ou fazer outras formatações. # # Copyright: GPL #

# Configuração do usuário caixa_largura=60 caixa_coluna_inicio=5 caixa_linha_inicio=5 texto_max_linhas=20 distancia_borda_texto=1 caixa_cor='33;1' texto_cor='32' #caixa_cor='33;43' # descomente essa linha para uma surpresa!

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− # Daqui pra baixo não mexa

### Configuração Dinâmica caixa_coluna_fim=$(( caixa_coluna_inicio+caixa_largura−1)) texto_coluna_inicio=$((caixa_coluna_inicio+distancia_borda_texto+1)) texto_largura=$(( caixa_largura−distancia_borda_texto)) texto=$( fmt −sw $texto_largura) num_linhas=$( echo "$texto" | wc −l) total_linhas=$(( num_linhas+2)) # texto + bordas horizontais

### Checagem do tamanho do texto if [ $num_linhas −gt $texto_max_linhas ];then echo "Texto muito extenso, não vai caber na tela" exit 1 fi

### Compõe a linha horizontal da caixa # É $caixa_largura−2 porque os "cantos" serão feitos com o +

AULA 4 − A Caixa de Ferramentas

63 Dono: Flávio Cunha

Page 68: Apostila Shell Flavio

for i in $(seq $((caixa_largura−2))); do linha_caixa="$linha_caixa−" done

### Limpa a tela echo −ne '\033c'

### Desenha a caixa echo −ne "\033[$caixa_linha_inicio;0H" # pula p/a linha inicial echo −ne "\033[${caixa_cor}m" # liga a cor da caixa for i in $(seq $total_linhas); do # para cada linha... echo −ne "\033[${caixa_coluna_inicio}G" # vai p/coluna inicial if [ $i −eq 1 −o $i −eq $total_linhas ]; then # 1a ou última linha echo +$linha_caixa+ # borda horizontal else # senão echo −e "|\033[${caixa_coluna_fim}G|" # bordas verticais fi done echo −e '\033[m' # desliga as cores

### Coloca o texto dentro da caixa echo −ne "\033[$((caixa_linha_inicio+1));0H" # pula p/a linha inicial echo −ne "\033[${texto_cor}m" # liga a cor do texto echo "$texto" | while read LINHA; do # para cada linha... echo −e "\033[${texto_coluna_inicio}G$LINHA" # posiciona e mostra done echo −e '\033[m' # desliga as cores echo

AULA 4 − A Caixa de Ferramentas

64 Dono: Flávio Cunha

Page 69: Apostila Shell Flavio

AULA 5 − Quem tem Medo de Expressões Regulares?

Expressões Regulares

Expressões Regulares. Um assunto que muitos torcem o nariz ao ouvir falar, mas que sempre acabaaparecendo na resolução dos mais diversos problemas.

Para quem não conhece ou não domina o assunto, é difícil perceber a utilidade de saber escrever todosaqueles símbolos estranhos. Mas à medida que vai se aprendendo, aplicando, tudo começa a clarear.

Veremos apenas o básico do básico das Expressões Regulares. O mínimo necessário para saber comoaplicá−las. O conhecimento mais aprofundado só será necessário caso o programador realmente precise.

O que são Expressões Regulares

Uma Expressão Regular (ER) é um método formal de se especificar um padrão de texto.

É uma composição de símbolos, caracteres com funções especiais, chamados "metacaracteres" que,agrupados entre si e com caracteres literais, formam uma seqüência, uma expressão. Essa expressão étestada em textos e retorna sucesso caso esse texto obedeça exatamente a todas as suas condições. Diz−seque o texto "casou" com a expressão.

A ERs servem para se dizer algo abrangente de forma específica. Definido o padrão de busca, tem−se umalista (finita ou não) de possibilidades de casamento. Em um exemplo rápido, [rgp]ato pode casar "rato","gato" e "pato".

As ERs são úteis para buscar ou validar textos variáveis como:

data• horário• número IP• endereço de e−mail• endereço de Internet• declaração de uma função()• dados na coluna N de um texto• dados que estão entre <tags></tags>• número de telefone, RG, CPF, cartão de crédito•

Vários editores de texto e linguagens de programação têm suporte a ERs, então o tempo investido em seuaprendizado é recompensado pela larga variedade de aplicativos onde ele pode ser praticado.

Os Metacaracteres

As expressões são apenas pequenos pedacinhos simples que agrupados formam algo maior. O importante écompreender bem cada um individualmente, e depois apenas lê−los em seqüência.

Estes pedacinhos podem ser caracteres literais como "a", "9" e "@", ou podem ser um ou maismetacaracteres, que possuem significados especiais.

65 Dono: Flávio Cunha

Page 70: Apostila Shell Flavio

Lista dos Principais Metacaracteres

Meta Nome Posicionamento

^ circunflexo Casa o começo da linha

$ cifrão Casa o fim da linha

Texto

[abc] lista Casa as letras 'a' ou 'b' ou 'c'

[^abc] lista negada Casa qualquer caractere, exceto 'a', 'b' e 'c'

(esse|aquele) ou Casa as strings 'esse' ou 'aquele'

Quantidade

a{2} chaves Casa a letra 'a' duas vezes

a{2,4} chaves Casa a letra 'a' de duas a quatro vezes

a{2,} chaves Casa a letra 'a' no mínimo duas vezes

Curingas

. ponto Casa um caractere qualquer

.* curinga Casa qualquer coisa, é o tudo e o nada

Atenção: Não confundir os metacaracteres com os curingas do Shell. Na linha de comando usa−se "*.txt","arquivo−??.txt" e "arquivo.{txt,html}" para expressar mais de um arquivo. Estes são curingas, enão metacaracteres.

Há uma similaridade e equivalência entre as ações, mas ERs são usadas em programas como grep, sed eawk, e os curingas são usados na linha de comando, para expandir nomes de arquivos.

Equivalência Entre Curingas do Shell e ERs

Shell ERs

* .*

? .

{,} (|)

Conhecendo Cada um dos Metacaracteres

Começando pelos metacaracteres de posicionamento, o circunflexo indica o início da linha, e o cifrão o final.Então o seguinte comando:

$ grep ^root /etc/passwd

Procurará pela string "root" somente no início das linhas, e não no meio. De maneira similar, o seguintecomando mostra todos os usuários que usam o bash como seu Shell de login, que é a última informação dasua linha no arquivo passwd:

$ grep bash$ /etc/passwd

Esse cifrão não é o mesmo cifrão usado para identificar variáveis! Então a primeira grande regra das ERs é:sempre use aspas. Isso evitará confusão com a expansão do Shell.

Uma ER pequenininha e que sempre acaba sendo utilizada, é que procura por linhas em branco. O que é umalinha em branco senão um começo de linha seguido de um fim de linha?

AULA 5 − Quem tem Medo de Expressões Regulares?

66 Dono: Flávio Cunha

Page 71: Apostila Shell Flavio

$ grep '^$' /etc/passwd

Mas nem só de posicionamento são os problemas, então é preciso de outros metacarateres. A lista é um bemutilizado. Ela define um grupo de caracteres válidos para uma posição, assim:

$ grep '[Cc]arlos' /etc/passwd

Achará os dados do usuário Carlos, mesmo que seu nome tenha sido iniciado por uma letra minúscula. A ERprocura por "Carlos" ou "carlos". Note que tudo o que está nos colchetes vale para uma posição somente, umaletra. Dentro dos colchetes, pode−se colocar tantos caracteres quantos necessários:

$ grep '^[aeiou]' /etc/passwd

Este comando procura por usuários que começam com vogais. Note o uso do circunflexo para "amarrar" apesquisa no início da linha. Para fazer o inverso, e obter os usuários que começam com consoantes,poderíamos listar todas elas dentro dos colchetes:

$ grep '^[bcdfghjkl...]' /etc/passwd

Mas as ERs nos dão uma maneira mais ágil de se fazer isso:

$ grep '^[^aeiou]' /etc/passwd

Caso o primeiro caractere dentro da lista seja um circunflexo, ele inverterá o sentido dessa lista, tornando−auma "lista negada". Ela casará qualquer caractere, EXCETO os listados após o "^". Então essa ER casaqualquer letra exceto as vogais.

Outra facilidade da lista é o intervalo. Basta colocar um hífen entre duas letras. Por exemplo "a−z" éinterpretado como "todas as letras entre a e z". Dessa maneira, é fácil procurar por linhas que contenhamnúmeros:

$ grep '[0−9]' /etc/passwd

[0−9] é igual a [0123456789] !

Às vezes, é necessário permitir "qualquer" caractere numa certa posição. Por exemplo, para procurar usuáriosonde a segunda letra do login seja uma vogal, como "mario", e "jose", mas não "ana":

$ grep '^.[aeiou]' /etc/passwd

O ponto casa qualquer caractere, seja letra, número, símbolo e até espaço em branco. Então essa ER diz: "Apartir do começo da linha, procure qualquer caractere seguido de uma vogal".

De maneira similar é possível procurar por linhas que tenham exatamente 10 caracteres:

$ grep '^..........$' /etc/passwd

Será que ali tem 10 pontos mesmo? Como saber ao certo? Novamente, as ERs nos dão ferramentas maisflexíveis para fazer a pesquisa. Colocando um número entre chaves, indica−se uma quantidade de repetiçõesdo caractere (ou metacaractere) anterior:

$ egrep '^.{10}$' /etc/passwd

.{10} é igual a .......... !

Essa expressão faz o mesmo que a anterior: procura por linhas que tenham 10 caracteres, quaisquer quesejam eles. A vantagem é que basta olhar o número de repetições, não precisa ficar contando os pontinhos.

Note que foi usado o egrep e não o grep. É porque as chaves fazem parte de um conjunto avançado deExpressões Regulares ("extended"), então o egrep lida melhor com elas. Se fosse para usar o grep normal,teria que "escapar" as chaves:

AULA 5 − Quem tem Medo de Expressões Regulares?

67 Dono: Flávio Cunha

Page 72: Apostila Shell Flavio

$ grep '^.\{10\}$' /etc/passwd

Feio! Vamos usar somente o egrep daqui pra frente para evitar tais escapes. As chaves também aceitamintervalos, sendo possível procurar por linhas que tenham de 10 a 20 caracteres:

$ egrep '^.{10,20}$' /etc/passwd

Ou, no mínimo 10, ou seja, de 10 ao infinito:

$ egrep '^.{10,}$' /etc/passwd

Como um login é composto por letras e números, agora fica fácil procurar todos os usuários que têm até 4caracteres no login:

$ egrep '^[a−z0−9]{1,4}:' /etc/passwd

Traduzindo: a partir do começo da linha (^), procure por letras e números em quantidade de uma até quatrovezes, seguido de dois−pontos. Isso casa os logins "ana" e "jose", mas não "mario" que tem 5 letras.

E para finalizar, o curinga ponto−asterisco. Ele significa "qualquer coisa", podendo ser "nada" ou "tudo", é útilquando realmente não interessa o miolo de uma ER, pode ser qualquer coisa que tanto faz. Como exemplo,para encontrar os usuários que começam com vogais e usam o Shell bash, faz−se:

$ egrep '^[aeiou].*bash$' /etc/passwd

Ou seja, procuramos por uma linha que comece com uma vogal e termine com a string "bash", nãoimportando o que tem no meio. Essa ER funcionou mais ou menos como um AND lógico, onde só casa setiver as duas pesquisas.

Para fazer o OR lógico, onde se procura por uma coisa ou outra, deve−se usar o pipe e delimitar com osparênteses:

$ egrep '^(mario|jose|ana):' /etc/passwd

Essa ER casa apenas as linhas dos três usuários citados. Ela começa procurando no início da linha (^),depois procura ou a string "mario", ou a string "jose", ou a string "ana", seguido pelo dois−pontos.

Detalhes, detalhes, detalhes

Outros metacaracteres que podem ser usados são o asterisco, o mais e a interrogação (chamado opcional).Eles definem quantidades e funcionam como as chaves, porém com uma sintaxe mais prática:

Meta Nome Equivalente Descrição

? opcional {0,1} Pode aparecer ou não (opcional)

* asterisco {0,} Pode aparecer em qualquer quantidade

+ mais {1,} Deve aparecer no mínimo uma vez

O intervalo "a−z" não inclui os caracteres acentuados! Então para procurar por letras minúsculas num textoem português, deve−se fazer "[a−záéíóúàâêôãõç]", ou caso o sistema esteja corretamente configuradopara o português, usar a classe especial "[[:lower:]]". Similarmente, use "[[:upper:]]" para asmaiúsculas.

Dependendo do aplicativo, a sintaxe das ERs pode ser diferente da do egrep. No sed e awk por exemplo (bemcomo no grep), as chaves e o "ou" devem ser escapados para serem especiais. Então o último exemplo ficariaassim no grep:

$ grep '^\(mario\|jose\|ana\):' /etc/passwd

AULA 5 − Quem tem Medo de Expressões Regulares?

68 Dono: Flávio Cunha

Page 73: Apostila Shell Flavio

Programa opc mais chaves borda ou grupo

awk ? + − − | ()

egrep ? + {,} \b | ()

emacs ? + − \b \| \(\)

find ? + − \b \| \(\)

gawk ? + {,} \<\> | ()

grep \? \+ \{,\} \b \| \(\)

sed \? \+ \{,\} \<\> \| \(\)

vim \= \+ \{,} \<\> \| \(\)

Há programas para auxiliar o aprendizado de Expressões Regulares. O txt2regex(http://txt2regex.sourceforge.net) é um programa modo texto feito 100% em Shell (bash2), e constrói ERsapenas mostrando menus ao usuário, que escolhe o que quer. Já para a interface gráfica, tem o Regex Coach(http://www.weitz.de/regex−coach/), com versões para Linux e Windows.

Para aprofundar−se no assunto, leia o livro "Expressões Regulares", disponível online em http://aurelio.net/er.A lista de discussão sed−br é um lugar onde dúvidas podem ser tiradas:http://br.groups.yahoo.com/group/sed−br.

Parsing de Código HTML, XML e Semelhantes

A grande característica de códigos HTML, XML e semelhantes é possuir marcações, chamadas TAGS, quesão identificadas por sinais de menor e maior, que delimitam uma palavra chave, podendo possuir opções.Exemplos: <b>, <hr>, <body bgcolor="white">

A pergunta mais freqüente nesse tipo de arquivos é: como tirar todas as tags, deixando apenas o texto?

$ echo '<p><b><i>negrito itálico</i></b></p>' | sed 's/<[^>]*>//g' negrito itálico

Esse comandinho minúsculo do sed, que usa Expressões Regulares, diz: "apague todas as marcações toformato <...>". No caso, o conteúdo da tag foi indicado como "[^>]*" que significa "qualquer coisa fora um >,em qualquer quantidade". Nesse caso não dá pra usar o curinga .*, veja o porque:

$ echo '<p><b><i>negrito itálico</i></b></p>' | sed 's/<.*>//g'

Toda a linha foi apagada! É que como o curinga é "guloso", ele foi casando "qualquer coisa" até o fim da linha,considerando a linha toda uma tag, de conteúdo "p><b><i.../b></p".

AULA 5 − Quem tem Medo de Expressões Regulares?

69 Dono: Flávio Cunha

Page 74: Apostila Shell Flavio

No HTML uma marcação muito usada e procurada quando se precisa extrair dados, é a TAG de link: "<a>".Sua sintaxe é:

<a href=" URL "> NOME </a>

Sendo a opção "href" quem guarda o endereço do link, e o todo o texto colocado entre as duas tags é o nomedo link, que será mostrado no navegador. Um exemplo:

<a href="http://google.com.br">Google</a>

No navegador aparecerá o texto Google, e ao clicar nele a URL "http://google.com.br" será acessada.

Para nós programadores, uma página HTML significa um brinquedo novo! Dados e textos juntos num mesmoarquivo precisam ser separados &:) Como primeira tarefa, dado um texto qualquer, extrair o endereço (URL)para o qual ele aponta, caso seja um link. Esta é a página de exemplo:

<html> <body> <p>Acesse a página do <a href="http://www.google.com.br">Google</a>. </p> </body> </html>

Uma página simples, com um link apenas. Tarefa: extrair a URL do texto "Google". Primeiramente, o principalé "pescar" a linha correta e excluir as demais:

$ fgrep Google pagina1.html <a href="http://www.google.com.br">Google</a>.

Fácil, facílimo. Agora falta pegar a URL, que está dentro das aspas. Deve haver umas 74 maneiras de fazerisso, usando sed, awk, IFS... Mas o cut parece ser a alternativa mais eficiente:

$ fgrep Google pagina1.html | cut −d\" −f2 http://www.google.com.br

AULA 5 − Quem tem Medo de Expressões Regulares?

70 Dono: Flávio Cunha

Page 75: Apostila Shell Flavio

Usando as aspas duplas como delimitador, extraia o segundo campo. As aspas precisam ser escapadas paraevitar problemas com o Shell. Tem algo errado aqui, não acha? Foi fácil demais! Geralmente se algo foi muitofácil de resolver, é porque o problema foi subestimado.

A página de exemplo estava muito fácil. Vamos complicá−la um pouco:

<html> <body> Você conhece o Google? <p>Acesse a página do "melhor", o <a href="http://www.google.com.br">Google</a>. </p> </body> </html>

Pronto, nossa "solução" não funciona mais:

$ fgrep Google pagina2.html | cut −d\" −f2 Você conhece o Google? melhor

O primeiro problema, é que o fgrep está muito genérico, e pega linhas além da desejada. E o esquema do cutnão funciona mais, pois há outras aspas na mesma linha do link.

Para resolver o fgrep, é necessário não somente procurar pelo texto, mas especificamente pelo texto somentese ele estiver dentro de tags de link "<a></a>":

$ fgrep '>Google</a>' pagina2.html "melhor", o <a href="http://www.google.com.br">Google</a>.

OK. O texto deve terminar com um "</a>" e deve ter um ">" antes, que é o final do "<a href". Agora vem aparte divertida: tirar o lixo! O sed é um bom candidato. Começando, tudo o que vier até o href=" deve serapagado:

$ fgrep '>Google</a>' pagina2.html | sed 's/.*href="//' "http://www.google.com.br">Google</a>.

O sed trocou "qualquer coisa" seguida da string href=" por nada. Legal, o endereço já está no começo dalinha, então agora falta arrancar o lixo do final. Aparentemente apagado tudo o que vier depois das aspas é osuficiente.

$ fgrep '>Google</a>' pagina2.html | sed 's/.*href="// ; s/".*//' http://www.google.com.br

Feito! Está começando a complicar, mas ainda está longe de ser perfeito. Complicando um pouco mais apágina, foi mudada a linha do link:

"melhor", o <a hReF=HTTP://www.GOOGLE.com.br>Google</A>.

Ai ai ai, começou... O HTML permite que a URL seja colocada sem as aspas também. E tanto a URL quantoos nomes das tags podem ser em maiúsculas ou minúsculas, então "<a></a>" e "<A></A>" são iguais. Falouem maiúsculas e minúsculas, falou em −i no fgrep.

$ fgrep −i '>Google</a>' pagina3.html "melhor", o <a hReF=HTTP://www.GOOGLE.com.br>Google</A>.

Já o sed, algumas versões possuem a opção "i" e outras não. Mas ao invés de ter que adaptar o sed para lidarcom maiúsculas e minúsculas, podemos "trapacear" e converter a linha toda para minúsculas:

$ fgrep −i '>Google</a>' pagina3.html | tr A−Z a−z "melhor", o <a href=http://www.google.com.br>google</a>.

Como só precisamos da URL, não será um problema usar esta tática. Então agora basta fazer o sedreconhecer os links sem aspas:

AULA 5 − Quem tem Medo de Expressões Regulares?

71 Dono: Flávio Cunha

Page 76: Apostila Shell Flavio

$ fgrep −i '>Google</a>' pagina3.html | tr A−Z a−z | > sed 's/.*href=// ; s/>.*//' http://www.google.com.br

Funcionou! O comando foi quebrado em duas linhas para não ficar muito extenso. O "> " é o promptsecundário do Shell, que mostra que ele está esperando mais comandos.

O comando sed foi modificado para apagar os lixos quando o link vier sem as aspas. Mas e quando vier comaspas? Mmmmmmm, não vai funcionar. Mas bem, quem precisa de aspas afinal de contas, basta apagá−las!

$ fgrep −i '>Google</a>' pagina[23].html | tr A−Z a−z | tr −d \" | > sed 's/.*href=// ; s/>.*//' http://www.google.com.br http://www.google.com.br

Foi adicionado mais um tr para varrer as aspas e o comando funcionou tanto com a página 2 (link com aspas)como com a página 3 (link sem aspas). O "pagina[23].html" é um curinga do Shell, e não uma ExpressãoRegular!

E para complicar de vez, o HTML permite que uma tag ocupe várias linhas, uma loucura!

<html> <body> Você conhece o Google? <p>Acesse a página do "melhor", o <a hReF="HTTP://www.GOOGLE.com.br" >Google</A >. </p> </body> </html>

E agora, o que fazer? Tática Ninja: Se o problema mudar de forma e sua solução quebrar, ao invés de mudara solução, "desmude" a forma do problema. Nesse caso "desmudar", é fazer a tag estar novamente em umalinha apenas. O mais fácil no caso, é fazer o arquivo todo ficar em um linha para evitar problemas:

$ tr −d '\012' < pagina4.html <html><body>Você conhece o Google?<p>Acesse a página do"melhor", o <ahReF="HTTP://www.GOOGLE.com.br">Google</A>.</p></body></html>

Beleza! O tr apagou todas as quebras de linha, deixando todo o texto em uma única (e longa!) linha. Como sótem uma linha mesmo, o fgrep não é mais necessário. Mas para identificar somente o link do Google, épreciso que o sed seja melhorado:

$ tr −d '\012' < pagina4.html | tr A−Z a−z | tr −d \" | > sed 's%>google</a>.*%% ; s/.*href=//' http://www.google.com.br

O comando s/// foi usado com outro delimitador, ficando s%%% e apaga do texto do link em diante, até ofinal. Depois vem o outro s/// já conhecido que apaga o lixo do início da linha.

E agora o teste final em todas as quatro páginas, para ver se funciona em todos os casos:

$ for arq in pagina[1234].html; do > tr −d '\012' < $arq | tr A−Z a−z | tr −d \" | > sed 's%>google</a *>.*%% ; s/.*href=//' > echo ; done http://www.google.com.br http://www.google.com.br http://www.google.com.br http://www.google.com.br

Tudo certo.

AULA 5 − Quem tem Medo de Expressões Regulares?

72 Dono: Flávio Cunha

Page 77: Apostila Shell Flavio

Extraindo Dados Automaticamente da Internet

O conhecimento de lidar com marcações HTML pode ser ainda mais poderoso se combinado com umacoisinha sem importância dos dias de hoje: Internet.

São milhares de páginas, cada um com o seu próprio formato e disposição dos dados. Há várias informaçõesde uso rotineiro, até diário que precisam de um acesso a uma página específica para serem vistas.

Mas usando o Shell e suas ferramentas, é possível automatizar este processo de obtenção de informação,agilizando o acesso e economizando tempo. Ao invés de abrir o navegador, acessar a página, ignorar todosos banners e texto inútil para finalmente achar a informação, um programa em Shell pode fazer tudo issoautomaticamente, mostrando na tela apenas o texto importante.

O navegador em modo texto lynx, é um aliado poderoso. Ele pode baixar uma página HTML inteira com ocódigo, ou renderizá−la, mostrando apenas seu conteúdo. Como em ambos os casos ele manda a páginapara a saída padrão, o lynx é uma ótima ferramenta para usar com filtros.

Principais Opções do lynx

−dump Renderiza uma página HTML e manda para STDOUT

−source Baixa o fonte HTML de uma página e manda para STDOUT

−nolist Usado com o −dump, para omitir a listagem de links

−width Define a largura máxima do texto (o padrão é 80)

Exemplos:

$ lynx −dump −width=70 arquivo.html > arquivo.txt $ lynx −source http://google.com > google.html

ANÁLISE ACOMPANHADA: Como extrair as manchetes do site de notícias Yahoo!

$ ./yahoonews.sh

As últimas manchetes são:

− BC reduzirá taxas de recolhimento compulsório−−fonte − EUA atacam casa em Bagdá em meio a rumor de que Saddam era alvo − Deputada mais votada do Piauí morre aos 37 anos − Carro−bomba explode em aeroporto da Espanha − Filipinas anunciam fim de impasse com tropas rebeladas − França pedirá extradição de 'anjo da morte' argentino − Fidel Castro rejeita ajuda da União Européia a Cuba − Israel concorda em libertar 100 militantes islâmicos − Presidente da Libéria diz que mais de mil foram mortos no país − Revolução cubana enfrenta dissidentes e isolamento aos 50 anos

TAREFA EM AULA:

Fazer uma interface texto para o buscador Google

AULA 5 − Quem tem Medo de Expressões Regulares?

73 Dono: Flávio Cunha

Page 78: Apostila Shell Flavio

AULA 6 − Utilizando Arquivos de Configuração

Explicação do Conceito

Um arquivo de configuração é um arquivo que contém somente texto, que especifica como será ofuncionamento do programa que o utiliza. Dentro dele podem ter:

Informações sobre o usuário• Definições de limites de máximo e mínimo• Definições de parâmetros necessários para a execução do programa• Estados de "chaves" que ligam e desligam funcionalidades• Localização de arquivos externos• Definições de aparência do programa• Personalização de funcionamento•

O arquivo de configuração existe para facilitar a modificação de comportamento do programa, sem queprecise recompilá−lo ou editar seu código fonte. Quanto mais opções puderem ser "configuráveis", maior aflexibilidade do usuário para alterar o programa conforme suas necessidades.

Praticamente todo programa de médio e grande porte usa arquivos de configuração. É um canal decomunicação simples e eficiente entre o usuário e o programa.

Com isso, é obrigatório o programa saber ler o arquivo para aplicar as configurações do usuário, e gravá−lopara guardar possíveis mudanças feitas durante a execução do programa.

O nome do programa, ou trecho de código que lê e grava um arquivo de configuração, conhecendo suaestrutura, é "parser".

Apesar de na teoria esse esquema todo ser uma ótima idéia, na prática o que se percebe é um completo caos,uma fauna infindável de formatos de arquivos de configuração.

Ao invés de se criar e seguir um padrão internacional e termos um parser genérico, cada autor reinventa aroda e cria seu próprio formato super−especial, 30% melhor que todos os outros.

Com isso, para cada arquivo de configuração que se precise extrair ou gravar informações, é preciso escreverum parser específico, que conheça as regras daquele arquivo em especial.

Veremos adiante como se codifica um parser.

Definindo um Formato

Antes de pensar em utilizar um arquivo de configuração, primeiro é necessário escolher o formato que estearquivo terá. Este capítulo guiará a escolha desse formato.

Formatos de Arquivos Existentes

Para que se tenha uma idéia do quão variada e exótica é a implementação de arquivos de configuração, aquivai uma pequena amostra, colocando apenas partes de arquivos encontrados num sistema Linux.

Note que além do formato interno, o nome do arquivo também é algo que não segue um padrão. Temos *.cfg,*.conf, *.cnf, *rc, ...

Obs.: Como "Branco", entenda: espaço em branco ou TAB

Palavra−Chave, Brancos, Parâmetro

httpd.conf: Parâmetro pode estar ou não "entre aspas"

# # Timeout: The number of seconds before receives and sends time out.

74 Dono: Flávio Cunha

Page 79: Apostila Shell Flavio

# Timeout 300

# # ServerAdmin: Your address, where problems with the server should be # e−mailed. This address appears on some server−generated pages, such # as error documents. # ServerAdmin root@localhost

# # DocumentRoot: The directory out of which you will serve your # documents. By default, all requests are taken from this directory, # but symbolic links and aliases may be used to point to other # locations. # DocumentRoot "/var/www/default"

Palavra−Chave, Brancos, Parâmetro (opcional)

fvwmrc: Palavras−Chave sozinhas, sem parâmetros

# Fonts WindowFont −adobe−helvetica−medium−r−*−*−16−*−*−*−*−*−*−* Font −misc−fixed−medium−r−*−*−14−*−*−*−*−*−*−*

# Focus AutoRaise 5000 SloppyFocus

# MWM Emulation MWMBorders MWMDecorHints MWMFunctionHints MWMHintOverride

# Miscellaneous Stuff OpaqueMove 0 EdgeScroll 0 0 EdgeResistance 0 0

Palavra−Chave, Igual (espaçado ou não), Parâmetro (opcional)

lilo.conf: Seções seqüenciais iniciadas pela palavra 'other'

boot = /dev/hda map = /boot/map timeout = 500 prompt vga = normal read−only other = /dev/hda1 label = win other = /dev/hda2 label = linux

Palavra−Chave, Igual, Parâmetro

my.cnf: Seções seqüenciais iniciadas por [marcadores]

[mysql.server] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock

[mysqladmin] socket=/var/lib/mysql/mysql.sock

AULA 6 − Utilizando Arquivos de Configuração

75 Dono: Flávio Cunha

Page 80: Apostila Shell Flavio

[mysqld] datadir=/var/lib/mysql socket=/var/lib/mysql/mysql.sock

[mysql] socket=/var/lib/mysql/mysql.sock

Componente, Igual (espaçado ou não), Parâmetro Numérico

sysctl.conf: Palavra−Chave tipo orientada.a.objeto, 0 desliga, 1 liga

# If active, logs 'impossible' source addresses net.ipv4.conf.all.log_martians = 1

# If active, rewrites outgoing IP packets if address changes net.ipv4.ip_dynaddr = 1

# If active, ignores ICMP with broadcast destination net.ipv4.icmp_echo_ignore_broadcasts = 1

# If active, accepts IP packets with source route info net.ipv4.conf.all.accept_source_route = 0

# If active, ignores all ICMP requests net.ipv4.icmp_echo_ignore_all = 0

Comando, Brancos, Palavra−Chave, Brancos, Parâmetro

inputrc: Parâmetros pré−definidos: on, off, outros.

set bell−style visible set meta−flag on set convert−meta off set output−meta on set editing−mode vi set completion−ignore−case on

Comando, Brancos, Palavra−Chave, Brancos, Igual (sem espaçamento), Parâmetro (opcional)

vimrc: Aspas duplas indicam comentários.

set aw "AutoWrite: gravacao automatica a cada alteracao set ai "AutoIndent: identacao automatica set ts=4 "TabStop: numero de caracteres de avanco do TAB set report=0 "reporta acoes com linhas set shm=filmnrwxt "SHortMessages: encurta as mensagem do rodape "set et "ExpandTab: troca TABs por espacos "retab "converter os TABs ja existentes

Palavra−Chave, Dois−pontos (sem espaçamento), Parâmetro

lynx.cfg: Formatação HTML embutida (.h1, .h2) para gerar documentação

.h1 Interaction # These settings control interaction of the user with lynx.

.h2 SCROLLBAR # If SCROLLBAR is set TRUE, Lynx will show scrollbar on windows. With # mouse enabled, the scrollbar strip outside the bar is clickable, and # scrolls the window by pages. The appearance of the scrollbar can be # changed from LYNX_LSS file: define attributes scroll.bar, # scroll.back (for the bar, and for the strip along which the

AULA 6 − Utilizando Arquivos de Configuração

76 Dono: Flávio Cunha

Page 81: Apostila Shell Flavio

# scrollbar moves). SCROLLBAR:FALSE

.h2 SCROLLBAR_ARROW # If SCROLLBAR_ARROW is set TRUE, Lynx's scrollbar will have arrows at # the ends. With mouse enabled, the arrows are clickable, and scroll # the window by 2 lines. The appearance of the scrollbar arrows can # be changed from LYNX_LSS file: define attributes scroll.arrow, # scroll.noarrow (for enabled−arrows, and disabled arrows). An arrow # is "disabled" if the bar is at this end of the strip. SCROLLBAR_ARROW:TRUE

Palavra−Chave, Arroba (opcional)

lpd.conf: O "@" no final da Palavra−Chave a desliga

# Purpose: open the printer for reading and writing # default rw@ (FLAG off) # Purpose: save job when an error # default save_on_error@ (FLAG off) # Purpose: save job when done # default save_when_done@ (FLAG off) # Purpose: send block of data, rather than individual files # default send_block_format@ (FLAG off) # Purpose: send data files first, then control file # default send_data_first@ (FLAG off)

Código Lisp

mesa.conf: A configuração é feita com código em Lisp!

;; Default profile − should normally be an empty list of ;; configurations. ;; (config−mesa mesa3.1beta1 ())

;; Really is an empty config. ;; (config−mesa empty ())

Análise dos Formatos Apresentados

Um arquivo de configuração é formado basicamente por quatro componentes:

Palavra−Chave: Define qual característica do programa está em foco

Valor: Define qual será o comportamento dessa característica

Separador: Caractere que separa a Palavra−Chave do Valor

Comentário: Caractere que "desliga" um linha

Pela análise dos exemplos, podemos notar que no geral:

Palavra−ChaveÉ formada apenas de letras e números, tendo como opcionais o hífen e o sublinhado([A−Za−z0−9_−]). Exemplos: use−color, WindowFont e EXEC_PATH

ValorO mais simples é apenas numérico, mas também pode ser do tipo liga/desliga (0/1, ON/OFF,TRUE/FALSE) ou "string". Exemplos: 123, OFF e "~/mail"

Separador

AULA 6 − Utilizando Arquivos de Configuração

77 Dono: Flávio Cunha

Page 82: Apostila Shell Flavio

É necessário para que a Palavra−Chave e o Valor nãofiquemgrudados. Geralmente se usa o sinal deigual "=", podendo ou não ter brancos (espaços e TABs) ao redor. Outros omitem o sinal e usam opróprio branco como separador, facilitando a leitura.

ComentárioÉ útil para desabilitar uma opção ou colocar textos explicativos. É quase uma unanimidade usar ocaractere "#". Poucos transgressores usam alternativas como aspas, ponto−e−vírgula ou "//". Além desaber qual o caractere de comentário, também é preciso saber como aplicá−lo. Estes são os tipos:

Válido apenas se começar bem no início da linha

# Eu começo já na coluna 1

1.

Válido no início da linha, mas pode ter brancos antes

# Eu tenho uns espaços e TABs antes

2.

Válido após o Valor, desligando apenas metade da linha (raro)

usar_som = ON # Eu vou na mesma linha da configuração

3.

Um quinto componente que pode ser encontrado é o "indicador de início de seção", usado em arquivos deconfiguração complexos que exigem contexto.

Escolhendo um Formato

Se sua necessidade é ler um arquivo de configuração já existente, não há escolha; seu parser devereconhecer aquele formato. Mas se você tem um programa e quer fazer um arquivo de configuração para ele,qual formato utilizar?

Pelas amostras e pela análise, é possível trilhar um "caminho comum", que seriam as características maismarcantes encontradas.

Formato Básico:

# comentário chave valor

O formato usando Brancos como separador é o mais simples e fácil de ler e os comentários com '#' já são umclássico. Podemos permitir brancos no início e final da linha (que serão ignorados no processamento), bemcomo vários brancos entre a Chave e o Valor.

Basicamente este é formato do arquivo de configuração do Apache (httpd.conf), que além de muito utilizado econhecido, é bem recheado e completo.

Especificação do FormatoO Comentário é do tipo linha inteira, iniciado por "#" e pode ser precedido por Brancos;◊ A Chave fica no início da linha e pode ser precedida por Brancos;◊ O Valor fica após a Chave, separado por um ou mais Brancos;◊ A Chave pode ser composta por letras e números somente;◊ O valor pode ser qualquer string ou número.◊

Descritivo do Formato <brancos opcionais> # comentário <brancos opcionais>

<brancos opcionais> chave <um ou mais brancos> valor <brancos opcionais>

Expressões Regulares do Formato ^ \s* # .* \s* $

^ \s* [A−Za−z0−9]+ \s+ .* \s* $

Agora que já temos um formato definido, podemos começar a programar, não?

AULA 6 − Utilizando Arquivos de Configuração

78 Dono: Flávio Cunha

Page 83: Apostila Shell Flavio

O Parser

Codificação Acompanhada de um Parser

Conforme já visto, o Parser é o programa ou código que "gerencia" arquivos de configuração. Ele sabe comoler e extrair os dados do arquivo, respeitando seu formato. Se necessário, o Parser também pode alterar oureescrever o arquivo.

Vamos começar com um exemplo simples, mas que ilustra a maioria dos aspectos envolvidos na escrita doParser. Mas antes é claro, precisa ter algo pra alimentar o Parser. A primeira ação é escrever um arquivo deconfiguração pequeno e simples, para ser usado nos testes.

Arquivo de Configuração de Testes

# ## mensagem.conf − O arquivo de configuração do mensagem.sh #

### Opções Liga/Desliga # # Use ON/OFF para ligar e desligar as opções UsarCores ON

### Opções Numéricas # # COR | LETRA | FUNDO # −−−−−−−−−−−+−−−−−−−+−−−−−−− # preto | 30 | 40 # vermelho | 31 | 41 # verde | 32 | 42 # amarelo | 33 | 43 # azul | 34 | 44 # rosa | 35 | 45 # ciano | 36 | 46 # branco | 37 | 47 # CorFundo 44 CorLetra 37

### Opções com Strings # Mensagem Modo texto é legal

Este é um arquivo que define o comportamento do script mensagem.sh, que serve para mostrar umamensagem na tela.

Supondo que o script seja executado com esta configuração, a sua saída será assim:

Tarefa 1Escrever o mensagem.sh. Este script lê o arquivo de configuração mensagem.conf, identifica aschaves, aplica os valores encontrados. Estes valores definem qual a mensagem a ser mostrada e emquais cores ela vai aparecer.

AULA 6 − Utilizando Arquivos de Configuração

79 Dono: Flávio Cunha

Page 84: Apostila Shell Flavio

Evolução para um Parser Genérico

A experiência de ter codificado o mensagem.conf pode ser usada para se dar um passo maior, maisprofissional: um Parser Genérico.

Imagine que você queira usar um arquivo de configuração com este mesmo formato em outro programa. Esseprograma também precisará de um Parser para gerenciar a configuração. Como o código feito para omensagem.sh está intrínseco a ele, seria feito o famoso Copiar/Colar para colocar o Parser dentro doprograma novo.

Mas esta é hora em que se diferenciam os profissionais dos amadores. Ter o mesmo código em dois lugaresnão é atitude de quem quer fazer programas de qualidade.

A situação exige que se escreva um script especialista, cuja função seja cuidar do arquivo de configuração enada mais, um verdadeiro gerente da configuração, o parser.sh.

Com o gerenciamento centralizado, qualquer programa que precisar de arquivos de configuração utilizará ogerenciador, e não precisará se preocupar em reimplementar as funções de Parser.

Mas como funcionaria esse Parser Genérico?

O código que lê e grava configurações vai estar todo contido no parser.sh. Mas como esse Parser vai secomunicar com os programas que vierem a utilizá−lo?

Por exemplo, se precisarmos mostrar na tela o conteúdo da configuração "Mensagem", presente nomensagem.conf. Como diremos isso ao Parser? Como ele irá nos mandar os dados?

Temos algumas opções:

O Parser pode ser uma biblioteca, um conjunto de funções que devem ser incluídas na Shell atual econforme chamadas, retornam os valores requisitados

$ CONF=mensagem.conf $ source parser.sh $ echo $(PegaValor Mensagem)

1.

O Parser pode ser um programa, que deve ser incluído na Shell atual e definirá variáveis de acordocom as configurações encontradas

$ CONF=mensagem.conf $ source parser.sh $ echo $MENSAGEM

2.

O Parser pode ser um programa, que recebe um arquivo como parâmetro e retorna na saída padrãotoda a configuração no formato chave=valor do Shell, pronto para ser usado com o comando eval

$ eval `./parser.sh mensagem.conf` $ echo $MENSAGEM

3.

Com certeza a primeira maneira é a mais profissional e parecida com a programação em linguagenstradicionais. Mas por hora vamos encará−la como um ideal a atingir, um refinamento futuro.

Para começar, a última maneira é a mais simples, pois é um programa autônomo, que funciona via opções delinha de comando. Esse Parser é na verdade um conversor, transformando texto em variáveis do Shell.

E olhe só como o Shell é poderoso. Sabia que podemos fazer um Parser que funcione nas três maneiras,com o mesmo código? Pois é, e você achava que Shell era só para fazer "scripts" &:)

O Parser do Tipo Conversor

Focalizando no modelo de Parser que funciona como um conversor, o esquema de comunicação entre ele e oprograma ficará assim:

AULA 6 − Utilizando Arquivos de Configuração

80 Dono: Flávio Cunha

Page 85: Apostila Shell Flavio

Ou seja, o Parser lê as configurações no formato chave valor e as converte para o formato de definição devariáveis do Shell chave="valor", mandando o resultado para a saída padrão. Tomando como exemplo oarquivo mensagem.conf, este seria o resultado:

$ ./parser.sh mensagem.conf USARCORES="ON" CORFUNDO="44" CORLETRA="37" MENSAGEM="Modo texto é legal"

Note que os nomes dos campos foram convertidos para maiúsculas. Isso serve para evitar problemas e trazerflexibilidade. Assim o usuário tem a liberdade de escrever os nomes das chaves com maiúsculas ouminúsculas, tanto faz. Por sua vez o programa sempre acessará a chave em maiúsculas.

Os valores são sempre colocados "entre aspas", sejam eles numéricos, liga/desliga ou texto. Lembre−se queem Shell não há tipagem explícita de dados, então 5, '5' e "5" são iguais.

Tarefa 2Escrever o parser.sh.

Tarefa 3Adaptar o mensagem.sh para que ele utilize o Parser.

AULA 6 − Utilizando Arquivos de Configuração

81 Dono: Flávio Cunha

Page 86: Apostila Shell Flavio

AULA 7 − Banco de Dados com Arquivos Texto

Explicação do Conceito

O Banco de Dados é um lugar específico para se guardar dados. O banco também manipula estes dados,apagando registros, incluindo novos, e alterando registros existentes. O tipo mais comum é o Banco de DadosRelacional.

Os Arquivos Texto são arquivos comuns do sistema, que contêm apenas texto comum, sem formatação ouimagens, como arquivos de configuração e mensagens simples de e−mail.

Geralmente, Bancos de Dados são sistemas complexos, que exigem instalação, configuração e manutenção.São feitos para gerenciar volumes imensos de informação em pouquíssimo tempo e possuem facilidadescomo desfazimento, becape (backup) e otimizações.

Já um Arquivo Texto é apenas um arquivo comum, que pode ser movido de um lugar para outro, transmitidopela Internet, guardado em disquete e editado em qualquer editor de textos, mesmo nos mais simples como"Bloco de Notas" ou "pico".

A idéia é juntar esses dois conceitos, implementando um Banco de Dados utilizando apenas Arquivos Texto, eter um produto novo: um banco de dados simples, porém de fácil manipulação, e extremamente portável.Isto é o "Banco de Dados com Arquivos Texto", ou abreviadamente "Banco Textual".

VantagensAcesso fácil ao banco: Sendo apenas um arquivo texto, pode−se usar qualquer editor parafazer manutenção no banco e alterar dados.

Portabilidade: O banco pode ser facilmente transmitido via Internet, E−mail, guardado emdisquete, e será o mesmo independente do Sistema Operacional. Pode−se inclusive "Copiar eColar" com o mouse o seu conteúdo, pois é apenas texto.

Compactável: Sendo somente texto, caso o banco fique com muitos dados, é possívelcompactá−lo para que seu tamanho fique reduzido. Embora para bancos muito grandes osarquivos texto não são aconselháveis, pois fica lento o acesso.

Simplicidade: O grande trunfo desse banco é ser simples. Sendo assim, é fácil compreendersua estrutura, editá−lo e escrever ferramentas para manipulá−lo.

DesvantagensPerformance: É rápido ler e manipular arquivos normais. Mas caso seu banco cresça muito(milhares de linhas), a velocidade de acesso vai ser prejudicada. Em outras palavras: vai ficarlento.

Relacionamentos: O banco em texto não tem relacionamentos entre os dados, entãocaracterísticas de Bancos de Dados normais como chaves estrangeiras ("foreign keys") etriggers não estão disponíveis. Até é possível de fazer, mas a complexidade de manter ocódigo torna mais viável a adoção de um Banco Relacional ao invés do textual.

Fragilidade: Sendo apenas um arquivo texto, o banco está sujeito aos "acidentes depercurso" que podem ocorrer com arquivos, como deleção acidental e edição descuidada(apagar conteúdo sem perceber). E por ser possível o acesso direto ao banco via editor detexto, são maiores as chances de se corromper os dados num erro de digitação.

Em resumo, a simplicidade é a maior vantagem do Banco de Dados Textual, mas por outro lado, é sua maiorlimitação. Antes de se decidir por usar o banco em texto, cabe uma análise prévia do caso e situaçãoespecífica, projeções de crescimento do banco e previsão da necessidade de operações avançadas.

De qualquer forma, mesmo que posteriormente se necessite migrar do banco texto para um relacional, oprocesso não é doloroso, pois texto é fácil de manipular. Já objetos e relacionamentos...

Onde Utilizar Bancos Textuais

Antes de começar a ver os detalhes do conceito, é bom conhecer quais são os usos comuns para esse tipo debanco.

82 Dono: Flávio Cunha

Page 87: Apostila Shell Flavio

Em programas especialmente, sempre se precisa guardar informações de estado, de configuração ou defuncionalidades. Como distribuir um banco de dados relacional com o seu programa não é uma alternativa, obanco simplificado brilha isolado. Alguns exemplos:

Guardar dados de estado para fins históricos, como quais foram os últimos arquivos abertos, asúltimas palavras pesquisadas, etc;

Guardar dados temporários, utilizados apenas em tempo de execução mas que precisam sergravados em disco para garantir consistência;

Guardar informações num formato intermediário, quando estiver fazendo conversões.• Guardar dados de configuração (Exemplo: /etc/passwd);•

Ou ainda, usar como base de aplicativos completos como:

Agenda de Contatos Pessoal• Catálogos de CDs ou arquivos mp3• Controle de Estoque Simples• Controle de CDs/fitas de becape• Controle de Tarefas com Estados (tipo TODO)• Qualquer cadastro de dados simples ou históricos•

Diferenças Estruturais dos Tipos de Banco

Um Banco de Dados Relacional possui alguns componentes e eles respeitam uma hierarquia interna. Umbanco pode ter várias "bases de dados". Cada uma dessas bases pode ter várias "tabelas", que se relacionamentre si. Cada tabela pode ter vários "campos", e cada campo guarda um "valor".

O Banco de Dados Textual, usa a própria hierarquia já existente no Sistema de Arquivos. Há diretórios, quecontêm arquivos, que contêm texto. Cada arquivo funciona como uma tabela de um Banco de DadosRelacional.

AULA 7 − Banco de Dados com Arquivos Texto

83 Dono: Flávio Cunha

Page 88: Apostila Shell Flavio

Como diretórios e arquivos são entidades já existentes no sistema, basta arranjar os dados dentro do arquivotexto. Que padrão utilizar? Um registro por linha? Um campo por linha? Todos os registros numa linha só?Como identificar os nomes dos campos?

Formato Interno do Arquivo Texto

A decisão de qual será o formato do arquivo texto, de como os dados ficarão arranjados, é crucial. Adificuldade em escrever os programas que acessarão o banco está diretamente relacionada ao projeto daestrutura interna do arquivo.

Quanto mais complexa a estrutura, mais difícil será codificar o "Gerenciador" desse banco. O ideal é que esteformato seja o mais simples possível, com poucas regras, porém consistentes.

Um formato famoso de disposição de dados em arquivos texto é o CSV (Comma Separated Values), quesignifica "Valores Separados por Vírgulas". É um formato simples, de poucas regras.

Especificação do formato CSV:

Um registro por linha;• A primeira linha contém os nomes dos campos;• As linhas seguintes são os dados;• Tanto os campos quanto os dados são separados entre si por vírgulas;• Números são colocados diretamente;• Textos são colocados "entre aspas";• Textos podem conter vírgulas, pois estão protegidas pelas aspas.•

Este formato é conhecido e largamente utilizado, sendo suportado por vários programas que manipulamdados, desde o Microsoft Excel até a Agenda de Endereços Online do Yahoo!

Exemplo Resumido do arquivo CSV do Yahoo! Endereços:

$ head −5 Yahoo.csv "Nome","Sobrenome","Apelido","E−mail","Fone","Celular" "Aurélio","Marinho Jargas","aurelio","[email protected]","","" "Milene","Pereira da Silva","milene","","","(41) 9999−1234" "João","Almeida","joao","[email protected]","234−5678","9999−5678" "","","zeca","[email protected]","432−9876",""

No exemplo, a primeira linha indica os nomes dos campos, colocados "entre aspas": Nome, Sobrenome,Apelido, E−mail, Fone e Celular. As linhas seguintes são os dados, um registro por linha, com os valores entreaspas e separados por vírgulas. Campos vazios são definidos com aspas vazias "".

Mas apesar de simples, esse formato tem o complicador das aspas, que torna a extração dos dados mais

AULA 7 − Banco de Dados com Arquivos Texto

84 Dono: Flávio Cunha

Page 89: Apostila Shell Flavio

complexa. Primeiro é preciso isolar os dados entre aspas (que podem conter vírgulas) para só depois dividiros registros em campos. Fica a pergunta: como colocar aspas literais? E outra: e se não fechar as aspas?

Para evitar esses "detalhes", vamos fazer uma especificação mais simples ainda, um derivado do CSV.

Simplificação do formato CSV:

Um registro por linha;• A primeira linha contém os nomes dos campos;• As linhas seguintes são os dados;• Tanto os campos quanto os dados são separados entre si por vírgulas;• Vírgulas literais são "mascaradas" com um caractere exótico.•

Os primeiros quatro itens são iguais aos do CSV, mas a grande diferença está no último. Para não precisar doesquema das aspas, simplesmente definimos a vírgula como único caractere especial, todos os outros sãoliterais. Caso algum dado contenha uma vírgula literal, esta será mascarada para um caractere exótico como"§" ou "£".

Então o seguinte banco em CSV:

"Nome","Endereço","Telefone" "Aurélio","Rua das Palmeiras, 789","234−5678"

Ficaria assim no formato simplificado:

Nome,Endereço,Telefone Aurélio,Rua das Palmeiras§ 789,234−5678

Ou seja, sem as aspas e com a vírgula literal no endereço trocada por um "§". Com isso simplificamos muito oformato do banco, porém perdemos a possibilidade de se colocar um "§" literal. Como cada escolha sempretraz os prós e contras, esse é o preço da simplificação. Por isso deve−se escolher um caractere realmenteexótico, para que a sua falta não seja um limitador em seu banco.

Escolhendo um Delimitador Melhor

Mas ainda podemos melhorar um pouco esse formato. A vírgula é um caractere muito comum de se encontrarem dados, como no endereço já citado e em números com casas decimais (os estrangeiros usam o ponto aoinvés da vírgula: 3.1415).

Usaremos então os dois−pontos ":" como o caractere delimitador de nosso banco textual. Apesar de comumem textos corridos, ele não aparece tanto em dados, e seu uso já é conhecido como delimitador, como noarquivo de usuários do UNIX, o /etc/passwd.

A Chave Primária

Tem ainda um último melhoramento a ser feito. No formato CSV não existe o conceito de "Chave Primária"(Primary Key). É básico num Banco de Dados, não se guardar informações repetidas. A Chave Primária servepara assegurar isso, não sendo possível cadastrar duas Chaves de mesmo conteúdo no Banco (UNIQUE).

A maneira mais limpa de introduzir o conceito de Chave Primária em nossa especificação, é considerar que oprimeiro campo definido será o identificador único. Ele pode ser um número serial, ou um nome, tanto faz.

Especificação do formato CSV simplificado:

Um registro por linha;• A primeira linha contém os nomes dos campos;• As linhas seguintes são os dados;• O primeiro campo é a chave primária (única);• Tanto os campos quanto os dados são separados entre si por dois−pontos;• Dois−pontos literais são "mascarados" com o caractere exótico "§".•

Voltando ao exemplo CSV do Yahoo, ele fica assim no formato simplificado:

AULA 7 − Banco de Dados com Arquivos Texto

85 Dono: Flávio Cunha

Page 90: Apostila Shell Flavio

$ head −5 Yahoo−simplificado.txt Apelido:Nome:Sobrenome:E−mail:Fone:Celular aurelio:Aurélio:Marinho Jargas:[email protected]:: milene:Milene:Pereira da Silva:::(41) 9999−1234 joao:João:Almeida:[email protected]:234−5678:9999−5678 zeca:::[email protected]:432−9876:

Note que o campo "Apelido" foi colocado por primeiro, pois ele é a Chave Primária desses dados.

É isso. Temos uma estrutura, temos uma especificação. Agora só falta a parte boa: programar.

O Gerenciador do Banco

Um banco sozinho não tem muita serventia. De que adianta guardar dados num formato especial se não setem ferramentas para manipulá−los?

Antes de sair programando uma agenda ou um catálogo de CDs, primeiro é preciso criar uma interface decomunicação com o Banco Textual, o componente chave que irá "falar" diretamente com o banco, o"Gerenciador de Banco de Dados".

Para quê serve o Gerenciador?

Imagine que você hoje vai escrever a Agenda de Contatos usando um Banco Textual. Você senta, codifica etermina. Está tudo funcionando. Mas se passam dois meses e agora você precisa escrever o Catálogo deCDs. O aplicativo é totalmente diferente, mas o miolo do código que cuida da inserção, edição e deleção dedados no Banco, é exatamente o mesmo!

Todos sabemos que ter o mesmo código em dois ou mais programas não é um bom negócio. Cada programasegue sua evolução natural e rapidamente aquele trecho que era "igual" em ambos, ficará irreconhecível. Asmelhorias do "miolo" de um não serão aplicadas ao outro, e logo logo cada um vai estar "conversando" com obanco de uma maneira diferente.

Daí surge−se a necessidade de se ter um programa especialista, específico para se comunicar com o Banco.Ele saberá como ler dados, incluir novos, apagar e alterar registros existentes. Será o mestre do Banco, oúnico programa que terá acesso direto a ele.

Os programas que usarão o Banco para guardar dados são os programas aplicativos, que cuidarão dainterface com o usuário e da manipulação dos dados extraídos do Banco. Nessa categoria se encaixam aAgenda e o Catálogo de CDs. Eles nunca acessarão o Banco diretamente, ao invés, farão requisições aoGerenciador, e este cuidará de executá−las.

Essa será a sua missão hoje: Escrever um Gerenciador de banco de Dados Textual.

AULA 7 − Banco de Dados com Arquivos Texto

86 Dono: Flávio Cunha

Page 91: Apostila Shell Flavio

Agora o Shell Entra na Conversa

Ao se pensar em qual linguagem implementar Gerenciador do Banco Textual, temos um candidato natural:falou em arquivos, falou em Shell!

Trabalhar com arquivos é básico no Shell, é o tipo de tarefa para a qual ele foi feito. Sua função é interagircom o sistema de arquivos (filesystem), provendo facilidades para o usuário gerenciar seus arquivos ediretórios.

Além do Shell, temos ao alcance uma vasta coleção de ferramentas especialistas em manipular texto, comosed, cut e grep. Elas fazem o trabalho pesado, transformando caracteres soltos em dados importantes.

Com a dupla Shell+Ferramentas, tem−se um ambiente completo para desempenhar as tarefas de:

Apagar, criar, alterar, copiar e mover arquivos• Apagar, incluir, alterar e mover linhas de arquivos•

São exatamente estas as características necessárias para se gerenciar os arquivos de texto do nosso Banco.

Descrevendo melhor a Tarefa do Dia:

Escrever um Gerenciador de Banco de Dados Textual em Shell com as seguintes características:Mostrar Registros♦ Apagar Registros♦ Inserir Registros♦ Modificar Registros♦

Programação do Gerenciador

Antes de pensar em codificar o Gerenciador, precisamos criar um Banco de Testes. Para simplificar oprocesso, vamos fazer um Banco pequeno, com poucos campos e dados distintos entre si.

Banco de Testes − Usuários do sistema:

login:nome completo:idade:sexo junior:Alfredo Vieira Júnior:12:M dani:Daniele Almeida Teles:19:F luciana:Luciana Silveira:22:F ana:Ana Paula de Souza:58:F mario:Mário da Silva:35:M ze:José Carlos Vaz:45:M

Inspirado no arquivo de usuários do sistema (/etc/passwd), temos um Banco simples. Na primeira linhaidentificamos quais são os campos:

Login (Chave Primária)• Nome completo• Idade• Sexo•

Pelos seus nomes já sabemos qual o tipo do se conteúdo. As linhas seguintes são os dados cadastradosnesse Banco. Temos 3 homens e 3 mulheres, com idades variadas.

O Gerenciador deve ser codificado com calma, atentando aos detalhes que cada ação possui. Por isso aTarefa do Dia foi divida em várias sub−tarefas.

Lista de Tarefas

Tarefa 1Codificar um programa Shell que receba um parâmetro da linha de comando e que apague do Bancode Testes o registro que tiver este parâmetro como Chave Primária (login). Mostrar mensagem na telacaso o registro seja apagado e caso não tenha sido encontrado.

AULA 7 − Banco de Dados com Arquivos Texto

87 Dono: Flávio Cunha

Page 92: Apostila Shell Flavio

Tarefa 2Codificar um programa Shell que inclua registros no Banco de Testes. O programa deve ser interativo,e pedir ao usuário para digitar o valor de cada campo, um por vez. Lembre−se que num Banco deDados não podem haver duas Chaves Primárias de mesmo conteúdo, e tampouco Chaves vazias!

Tarefa 3Codificar um programa Shell que mostre todos os dados do Banco de Testes de maneira clara, comos registros visualmente separados entre si e colocando um campo por linha, no formato"nome_do_campo: valor".

Outras TarefasAs demais tarefas serão passadas durante a aula.

AULA 7 − Banco de Dados com Arquivos Texto

88 Dono: Flávio Cunha

Page 93: Apostila Shell Flavio

AULA 8 − Interfaces Amigáveis com o Dialog

Apresentação

O Que é o Dialog

O Dialog é um programa para modo texto que desenha caixas de diálogo ("dialog boxes") na tela, similares asdo modo gráfico, com botões, entradas para texto e menu. Essas caixas são utilizadas para compor interfacesamigáveis com o usuário, para que ele responda perguntas ou escolha opções.

O Dialog é um executável e recebe todos os parâmetros via linha de comando. Serve para fazer programasinterativos, que o usuário precisa operar durante sua execução. Tarefas comuns feitas com o Dialog sãoescolher uma opção em um menu, escolher um arquivo, uma data, e digitar frases ou senhas.

Com o Dialog é possível fazer programas em Shell que se "parecem" com programas gráficos, onde o usuáriovê apenas telas e navega entre elas apertando os botões de "OK" e "CANCELAR". Exemplos clássicos dessetipo de interface são os programas de instalação de software.

Utilizando este conceito de telas, é possível "amarrar" o usuário ao programa, lhe apresentando as opçõesdisponíveis, sem que ele precise ter acesso direto à linha de comando. Útil para logins restritos e para ajudariniciantes.

Mas é melhor ver do que ler. Isto é Dialog:

$ dialog −−msgbox 'minha primeira tela' 5 40

Fácil não? Foi desenhada uma caixa de mensagens (−−msgbox) de 5 linhas por 40 colunas (Não confundircom pixels, pois estamos no console!).

89 Dono: Flávio Cunha

Page 94: Apostila Shell Flavio

Os Tipos de Caixa

O Dialog reconhece vários tipos de "caixas". A msgbox recém vista é uma das mais simples. Estes são ostipos de caixas suportadas pelo Dialog:

Tipo da caixa Desenha uma caixa onde o usuário...

calendar Vê um calendário e escolhe uma data

checklist Vê uma lista de opções e escolhe várias

fselect Digita ou escolhe um arquivo

gauge Vê uma barra de progresso (porcentagem)

infobox Vê uma mensagem, sem botões

inputbox Digita um texto qualquer

menu Vê um menu e escolhe um item

msgbox Vê uma mensagem e aperta o botão OK

passwordbox Digita uma senha

radiolist Vê uma lista de opções e escolhe uma

tailbox Vê a saída do comando tail −f

tailboxbg Vê a saída do comando tail −f (em segundo plano)

textbox Vê o conteúdo de um arquivo

timebox Escolhe um horário

yesno Vê uma pergunta e aperta o botão YES ou o NO

Linhas de Comando prontas para testar

dialog −−calendar 'abc' 0 0 31 12 1999

dialog −−checklist 'abc' 0 0 0 item1 'desc1' on item2 'desc2' off

dialog −−fselect /tmp 0 0

(echo 50; sleep 2; echo 100) | dialog −−gauge 'abc' 8 40 0

dialog −−infobox 'abc' 0 0

dialog −−inputbox 'abc' 0 0

dialog −−passwordbox 'abc' 0 0

dialog −−menu 'abc' 0 0 0 item1 'desc1' item2 'desc2'

dialog −−msgbox 'abc' 8 40

dialog −−radiolist 'abc' 0 0 0 item1 'desc1' on item2 'desc2' off

dialog −−tailbox /tmp/arquivo.txt 0 0

dialog −−textbox /tmp/arquivo.txt 0 0

dialog −−timebox 'abc' 0 0 23 59 00

dialog −−yesno 'abc' 0 0

AULA 8 − Interfaces Amigáveis com o Dialog

90 Dono: Flávio Cunha

Page 95: Apostila Shell Flavio

As Principais Opções de Linha de Comando

−−title <texto>Define o título da caixa, colocado centralizado na borda superior.

−−backtitle <texto>Especifica o título do topo da tela, que fica no plano de fundo, atrás da caixa (Veja exemplo do"Pegador de Dados").

−−no−shadowNão desenha a sombra da caixa.

−−no−cancel ou −−nocancelNão mostra o botão CANCELAR nas caixas Checklist, Inputbox e Menu. A tecla Esc continua valendopara sair da caixa.

−−defaultnoFaz o botão 'Não' ser o padrão da caixa YesNo.

−−cr−wrapMantém as quebras de linha originais do texto da caixa, para não precisar colocar os '\n'. Maslembre−se que caso a linha fique muito grande, o Dialog a quebrará no meio para caber na caixa.

−−trimLimpa o texto da caixa, apagando espaços em branco no início, espaços consecutivos e quebras delinha literais.

−−stdoutRetorna os dados na Saída Padrão (STDOUT) ao invés da STDERR.

−−separate−outputNa caixa Checklist, retorna os itens selecionados, um por linha e sem aspas. Bom para scripts!

−−sleep <N>Faz uma pausa de N segundos após processar a caixa. Útil para a Infobox.

−−print−maxsizeMostra o tamanho atual da tela na STDERR. (Obs.: Esta opção deve ser usada sozinha na linha decomando.)

Mais opções em "man dialog".

Como o Dialog Funciona

O Dialog é relativamente simples de usar, mas como ele age um pouco "diferente" dos outros programas dosistema, pode assustar e parecer confuso numa primeira tentativa.

Adiante veremos em detalhes como construir e obter dados das caixas, e aprenderemos algumascaracterísticas do Dialog como:

A linha de comando é longa, cheia de opções• Ele redimensiona o texto e a caixa automaticamente• Usa código de retorno para botões Sim/Não, Ok/Cancel• Usa a saída de erro (STDERR) para textos e itens escolhidos•

Entendendo os Parâmetros Obrigatórios da Linha de Comando

No Dialog, é obrigatório passar o texto e o tamanho da caixa, sempre. Com isso, a cada chamada doprograma, deve haver pelo menos 4 opções na linha de comando.

O formato genérico de chamada é:

dialog −−tipo−da−caixa '<texto>' <altura> <largura>

textoO texto é a palavra ou frase que aparece no início da caixa, logo após a primeira linha (bordasuperior). Passe uma string vazia '' caso não deseje texto. Caso o texto seja maior que o tamanho dajanela, ele será ajustado automaticamente, quebrando a linha. Para colocar as quebras de linhasmanualmente, insira o padrão '\n' (barra−ene) onde desejar as quebras. Exemplo: 'Primeiralinha.\nSegunda.'

AULA 8 − Interfaces Amigáveis com o Dialog

91 Dono: Flávio Cunha

Page 96: Apostila Shell Flavio

alturaA altura é o número de linhas que serão utilizadas para desenhar a caixa, inclusive a primeira e aúltima que fazem as bordas superior e inferior. Se informado o número zero, o Dialog ajustaautomaticamente a altura da caixa para caber o conteúdo.

larguraA largura é o número de colunas que serão utilizadas para desenhar a caixa, inclusive a primeira e aúltima que fazem as bordas esquerda e direita. Se informado o número zero, o Dialog ajustaautomaticamente a largura da caixa para caber o conteúdo.

Na prática, é melhor deixar que o Dialog quebre o texto e ajuste o tamanho das caixas automaticamente.Então nos exemplos desse documento não haverá quebras de linha manuais (\n) e os tamanhos serãosempre especificados como "0 0" (zero zero).

As caixas do tipo Menu (Menu, RadioList, CheckList), precisam de linhas de comando mais complexas, e têmoutras opções obrigatórias além das comuns para todas as caixas.

Este é o formato genérico da linha de comando da caixa Menu:

dialog −−menu '<texto>' 0 0 <núm−itens> <item1> <desc1> ... <itemN> <descN>

núm−itensO número máximo de itens do menu que serão mostrados na caixa. Os demais ficarão ocultos epodem ser acessados rolando a lista com as setas do teclado. Caso especificado como zero, o Dialogmostra todos os itens, ou ajusta automaticamente o número ideal para que a caixa caiba na tela.

itemO item deve ser um nome único, diferente para cada item. O item é o texto retornado pelo Dialog aoscript, quando o usuário escolhe uma opção.

descriçãoA descrição é um texto explicativo que serve para detalhar do que se trata o item. A descrição podeser omitida passando a string vazia ''. Exemplo: dialog −−menu 'texto' 0 0 0 item1 ''item2 '' item3 ''

Se for um CheckList ou RadioList, ainda deve−se colocar mais um argumento após cada item, que é "ON" ou"OFF", para dizer se o item já aparecerá selecionado ou não.

Como Reconhecer Respostas SIM ou NÃO

O Dialog utiliza o código de retorno ("Return Code") para informar qual foi o botão apertado:

$ dialog −−yesno 'sim ou não?' 0 0 ; echo Retorno: $?

Fácil! Zero para Sim, um para Não, assim como todos os outros comandos do sistema, se retornar zero é porestá tudo OK. Na prática, basta usar o if para testar o valor do $?:

dialog −−yesno 'Quer ver as horas?' 0 0

if [ $? = 0 ]; then echo "Agora são: $( date )" else echo 'Ok, não vou mostrar as horas.' fi

Usando o Dialog fica fácil definir flags antes da execução do programa! Por exemplo, um programa simplespara listar arquivos do diretório atual:

#!/bin/sh # lsj.sh −− o script do "ls joiado"

# Zerando as opções cor= ; ocultos= ; subdir= ; detalhes=

AULA 8 − Interfaces Amigáveis com o Dialog

92 Dono: Flávio Cunha

Page 97: Apostila Shell Flavio

# Obtendo as configurações que o usuário deseja dialog −−yesno 'Usar cores?' 0 0 && cor='−−color=yes' dialog −−yesno 'Mostrar arquivos ocultos?' 0 0 && ocultos='−a' dialog −−yesno 'Incluir sub−diretórios?' 0 0 && subdir='−R' dialog −−yesno 'Mostrar visão detalhada?' 0 0 && detalhes='−l'

# Mostrando os arquivos ls $cor $ocultos $subdir $detalhes

Como Obter a Resposta do Usuário

O funcionamento padrão do Dialog é: após o usuário digitar o texto ou escolher um item de menu e apertar oOK, esse texto/item é mandado para a saída de erro (STDERR). Há três maneiras de "pescá−lo":

Redirecionar a STDERR para um arquivo e ler o conteúdo desse arquivo1. Redirecionar a STDERR para a STDOUT2. Usar a opção −−stdout para desvira a saída para a STDOUT3.

A maneira mais limpa e fácil é a última, usando −−stdout, pois evita ter que usar o redirecionamento no Shell.Exemplos:

Obtendo um Texto

nome=$( dialog −−stdout −−inputbox 'Digite seu nome:' 0 0 ) echo "O seu nome é: $nome"

Obtendo o Item Escolhido (Menu, Radiolist)

cor=$( dialog −−stdout −−menu 'As cores:' 0 0 0 \ amarelo 'a cor do sol' \ verde 'a cor da grama' \ azul 'a cor do céu' ) echo Você escolheu a cor $cor

Obs.: Quebrar o comando em várias linhas é opcional, mas torna muito mais fácil a sualeitura.

Obtendo Itens Múltiplos (Checklist)

estilos=$( dialog −−stdout −−checklist 'Você gosta de:' 0 0 0 \ rock '' ON \ samba '' OFF \ metal '' ON \ jazz '' OFF \ pop '' ON \ mpb '' OFF ) echo "Você escolheu: $estilos"

O Dialog retorna todos os itens na mesma linha, protegidos por aspas duplas. Para ficar mais fácil extrairestes dados, existe a opção −−separate−output, que retorna os itens selecionados um por linha e sem asaspas:

estilos=$( dialog −−stdout −−separate−output \ −−checklist 'Você gosta de:' 0 0 0 \ rock '' ON \ samba '' OFF \ metal '' ON \ jazz '' OFF \ pop '' ON \ mpb '' OFF )

echo "$estilos" | while read LINHA; do echo "−−− $LINHA"; done

AULA 8 − Interfaces Amigáveis com o Dialog

93 Dono: Flávio Cunha

Page 98: Apostila Shell Flavio

O Botão CANCELAR e a Tecla Esc

Em alguns tipos de caixa, há o botão CANCELAR, que serve para o usuário "desistir" daquele passo. O apertodesse botão retorna código 1 (um), então basta testar o valor de $?:

[ $? −eq 1 ] && echo 'Botão CANCELAR apertado'

Já o Esc, pode ser usado em qualquer tela do Dialog, e gera o código de retorno 255. No geral, além de tratardo botão OK (retorno zero) e do CANCELAR (retorno 1), também é preciso cuidar da tecla Esc.

Dependendo do tipo de sua aplicação, a tecla Esc pode gerar o mesmo procedimento que apertar o botãoCANCELAR geraria. Ou ainda, pode−se ter dois procedimentos diferentes, um para cada evento. Tudodepende do tipo de navegação que seu programa utiliza, algumas sugestões:

Navegação amarrada a um Menu PrincipalSe apertar CANCELAR no Menu Principal, sai do programa◊ Se apertar CANCELAR numa tela secundária, volta ao Menu Principal◊ Se apertar ESC em qualquer tela, sai do programa◊

Navegação tipo Ida e VoltaSe apertar CANCELAR volta à tela anterior◊ Se apertar ESC sai do programa◊

Um tratador genérico para os tipos de retorno do Dialog é algo como:

case $? in 0) echo O usuário apertou o botão OK (ou o Yes) ;; 1) echo O usuário apertou o botão CANCELAR (ou o No) ;; 255) echo O usuário apertou a tecla ESC ;; *) echo Retorno desconhecido;; esac

Caso queira mapear o Esc para o mesmo funcionamento do CANCELAR, basta checar se o retorno foidiferente de zero:

[ $? −ne 0 ] && echo 'Esc ou CANCELAR apertado'

AULA 8 − Interfaces Amigáveis com o Dialog

94 Dono: Flávio Cunha

Page 99: Apostila Shell Flavio

Análise dos Tipos de Navegação de Telas

Menu Amarrado (em Loop)

#!/bin/bash # tia.sh − o script da tia que precisa usar o computador # # Exemplo de como amarrar o script num menu principal usando # o 'while'. O 'case' é usado para identificar qual foi a ação # escolhida. Após cada ação, ele sempre retorna ao menu # principal. Só sai do script caso escolha a última opção, # aperte CANCELAR ou ESC. # # Útil para usar como login shell de pessoas inexperientes ou # fazer utilitários de ações restritas e definidas. # # FLUXOGRAMA # INÍCIO FIM # +−−−−−−−−−−−+ +−−−−−−−−−−+ # +−−−−−−> | menu |−−Esc−−−−−> | sai do | # | | principal |−−Cancel−−> | programa | # | +−−−−−Ok−−−−+ +−−> +−−−−−−−−−−+ # | | | # +−−<−−1 2 3−4−−+−−Zero−−−>−−−+

# Loop que mostra o menu principal while : ; do

# Mostra o menu na tela, com as ações disponíveis resposta=$( dialog −−stdout \ −−title 'Menu da Tia' \ −−menu 'Oi Tia, escolha o quê você quer fazer:' \ 0 0 0 \ 1 'Navegar na Internet' \ 2 'Escrever uma carta' \ 3 'Jogar paciência' \ 4 'Perder tempo' \ 0 'Sair' )

# Ela apertou CANCELAR ou ESC, então vamos sair... [ $? −ne 0 ] && break

# De acordo com a opção escolhida, dispara programas case "$resposta" in 1) /usr/bin/mozilla 'http://google.com.br' ;; 2) /bin/mcedit /tmp/carta.txt ;; 3) /usr/games/solitaire ;; 4) /usr/X11R6/bin/xsnow ; /usr/X11R6/bin/xeyes ;; 0) break ;; esac done

echo 'Tchau Tia!' # Mensagem final :)

AULA 8 − Interfaces Amigáveis com o Dialog

95 Dono: Flávio Cunha

Page 100: Apostila Shell Flavio

Telas Encadeadas (Navegação Sem Volta)

#!/bin/sh # encadeado.sh − o script que chega até o final # # Exemplo de como encadear telas usando o operador && (AND). # Caso o usuário desista em qualquer tela (apertando CANCELAR # ou ESC), o script executa o primeiro comando após a cadeia # de &&. # # Útil para fazer programas ou brincadeiras onde só há um # caminho certo a seguir para chegar ao final. # # FLUXOGRAMA # INÍCIO # +−−−−−−−+ # | tela1 |−−Cancel/Esc−−−>−−−+ # +−−Ok−−−+ | # | tela2 |−−Cancel/Esc−−−>−−−+ +−−−−−−−−−−+ # +−−Ok−−−+ |−−−> | desistiu | # | tela3 |−−Cancel/Esc−−−>−−−+ +−−−−−−−−−−+ # +−−Ok−−−+ | # | tela4 |−−Cancel/Esc−−−>−−−+ # +−−Ok−−−+ # | final | # +−−−−−−−+ # FIM #

# Função rápida para chamar a caixa YesNo simnao(){ dialog −−yesno "$*" 0 0 }

# Aqui começa o encadeamento de telas com o &&. # Somente apertando o botão OK vai para a próxima tela. # Há um 'exit' no final, que sai do script caso o usuário # tenha chegado até o fim da cadeia. simnao 'Quer continuar?' && simnao 'Estamos na segunda tela. Continua?' && simnao 'Terceira. Continua continuando?' && simnao 'Penúltima tela! E agora, continua?' && echo 'Você chegou até o final!' && exit

# Este trecho já não faz mais parte do encadeamento, e só # será alcançado caso o usuário tenha apertado CANCELAR/Esc. echo Você desistiu antes de chegar no final...

AULA 8 − Interfaces Amigáveis com o Dialog

96 Dono: Flávio Cunha

Page 101: Apostila Shell Flavio

Navegação Completa (Ida e Volta)

#!/bin/bash # navegando.sh − o script que vai e volta # # Exemplo de como ligar todas as telas do programa entre si, # guardando informações de ida e volta. O botão CANCELAR faz # voltar para a tela anterior e o OK faz ir à próxima. Para # sair do programa a qualquer momento basta apertar o ESC. # # Útil para fazer programas interativos, de contexto, ou que # se pode voltar para corrigir informações. # # FLUXOGRAMA # INÍCIO # +−−−−−−−−−−−+ # | primeira |−−Esc−−−>−−−+ # .−−−−−−−−> +−−−−Ok−−−−−+ | # `−−Cancel−−| nome |−−Esc−−−>−−−+ # .−−−−−−−−> +−−−−Ok−−−−−+ | +−−−−−−−−−−+ # `−−Cancel−−| idade |−−Esc−−−>−−−+−−−> | Sai do | # .−−−−−−−−> +−−−−Ok−−−−−+ | | Programa | # `−−Cancel−−| est.civil |−−Esc−−−>−−−+ +−−−−−−−−−−+ # .−−−−−−−−> +−−−−Ok−−−−−+ | # `−−Cancel−−| gostos |−−Esc−−−>−−−+ # +−−−−Ok−−−−−+ # | final | # +−−−−−−−−−−−+ # FIM #

proxima=primeira

# loop principal while : ; do

# Aqui é identificada qual tela deve ser mostrada. # Em cada tela são definidas as variáveis 'anterior' # e 'proxima' # que definem os rumos da navegação. case "$proxima" in primeira) proxima=nome dialog −−backtitle 'Pegador de Dados' \ −−msgbox 'Bem−vindo ao pegador de dados!' 0 0 ;; nome) anterior=primeira proxima=idade nome=$(dialog −−stdout \ −−backtitle 'Pegador de Dados' \ −−inputbox 'Seu nome:' 0 0) ;; idade) anterior=nome

AULA 8 − Interfaces Amigáveis com o Dialog

97 Dono: Flávio Cunha

Page 102: Apostila Shell Flavio

proxima=casado idade=$(dialog −−stdout \ −−backtitle 'Pegador de Dados' \ −−menu 'Qual a sua idade?' 0 0 0 \ 'menos de 15 anos' '' \ 'entre 15 e 25 anos' '' \ 'entre 25 e 40 anos' '' \ 'mais de 40 anos' '' ) ;; casado) anterior=idade proxima=gostos casado=$(dialog −−stdout \ −−backtitle 'Pegador de Dados' \ −−radiolist 'Estado civil:' 0 0 0 \ 'solteiro' 'livre leve solto' ON \ 'noivo' 'quase amarrado' OFF \ 'casado' 'já era' OFF \ 'viúvo' 'livre de novo' OFF ) ;; gostos) anterior=casado proxima=final gostos=$(dialog −−stdout \ −−separate−output \ −−backtitle 'Pegador de Dados' \ −−checklist 'Do que você gosta?' 0 0 0 \ 'jogar futebol' '' off \ 'pescar' '' off \ 'ir ao shopping' '' off \ 'andar de bicicleta' '' off \ 'ficar na internet' '' off \ 'dormir' '' off ) ;; final) dialog \ −−cr−wrap \ −−sleep 5 \ −−backtitle 'Pegador de Dados' \ −−title 'Obrigado por responder' \ −−infobox " Os dados informados foram Nome : $nome Idade : $idade Casado: $casado Gostos: \n$gostos " 14 40 break ;; *) echo "Janela desconhecida '$proxima'." echo Abortando programa... exit esac

# Aqui é feito o tratamento genérico de Código de Retorno # de todas as telas. Volta para a tela anterior se for # CANCELAR, sai do programa se for ESC. retorno=$? [ $retorno −eq 1 ] && proxima=$anterior # cancelar [ $retorno −eq 255 ] && break # Esc

done

AULA 8 − Interfaces Amigáveis com o Dialog

98 Dono: Flávio Cunha

Page 103: Apostila Shell Flavio

EXTRAS

Para quem realmente gostar e usar muito o Dialog, aqui vão mais brinquedinhos.

Configurando as Cores das Caixas

É possível configurar as cores de todos os componentes das caixas, como textos, borda, botões e fundo datela. Dessa maneira pode−se personalizar os programas que usam o Dialog para a empresa ou indivíduo queo utilizará.

Para obter o arquivo padrão de configuração do Dialog, basta usar a opção −−create−rc. Como o programaprocura dentro de seu $HOME por um arquivo chamado .dialogrc, use este comando para começar abrincar de trocar as cores do Dialog:

dialog −−create−rc $HOME/.dialogrc

Agora basta editar o arquivo .dialogrc recém−criado no seu $HOME e executar o Dialog para ver adiferença. As cores que ele reconhece são:

BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN e WHITE

Que são respectivamente:

PRETO, VERMELHO, VERDE, AMARELO, AZUL, ROSA, CIANO e BRANCO

O formato das configurações de cores é:

nome_do_componente = (letra, fundo, letra brilhante?)

Onde para letra e fundo basta colocar os nomes das cores em inglês, e no terceiro parâmetro, coloque ON ouOFF para que as letras fiquem brilhantes ou não (claras ou escuras). Exemplo:

(GREEN, BLACK, OFF) = fundo preto, letra verde escuro

(GREEN, BLACK, ON) = fundo preto, letra verde claro

Depois de terminar de configurar as cores, você pode salvar tudo num arquivo separado, e fazer váriosarquivos diferentes para vários "temas" ou configurações diferentes.

Para instruir o Dialog a utilizar um arquivo de configuração específico, e não o padrão $HOME/.dialogrc,basta definir a variável de ambiente $DIALOGRC com o nome arquivo a ser utilizado, por exemplo:

export DIALOGRC=$HOME/dialog/tema−verde.cfg ./navegando.sh

AULA 8 − Interfaces Amigáveis com o Dialog

99 Dono: Flávio Cunha

Page 104: Apostila Shell Flavio

Fazendo Interfaces Realmente Gráficas

Agora uma ótima notícia para usuários de interface gráfica (XFree86). Existe o Xdialog(http://xdialog.dyns.net), que é o Dialog gráfico, usando a biblioteca Gtk+.

E a melhor parte, é que o Xdialog possui exatamente a mesma sintaxe na linha de comando do que o Dialog,ou seja, nenhuma adaptação é necessária para que scripts que utilizem o Dialog, rodem na interface gráficacom o Xdialog.

Além de fazer tudo o que o Dialog faz, o Xdialog ainda tem adicionais como botão de Help que chama a telade Ajuda da caixa e vários tipos novos de caixa como: treeview, buildlist, editbox, rangebox, logbox, spinboxes, combobox, colorsel e fontsel.

Para fazer o mesmo programa utilizar o Xdialog se estiver na interface gráfica, e o Dialog caso não esteja, ésimples. Primeiramente, troque todas as chamadas ao Dialog no programa, por $DIALOG, assim:

$DIALOG −−yesno "X é legal?" 0 0

Essa variável nova guardará qual o Dialog que vai ser usado, o console ou o gráfico. Para saber se o usuárioestá na interface gráfica ou não, basta checar a existência da variável $DISPLAY, que só é definida quando oX está sendo executado. Então bem no início do programa, coloque o seguinte teste:

if [ "$DISPLAY" ]; then DIALOG=xdialog else DIALOG=dialog fi

Simples e flexível. Perfeito.

−o−

TAREFA EM AULA:

Fazer uma Interface Dialog para o Mini−Gerenciador de Banco de Dados Textual

AULA 8 − Interfaces Amigáveis com o Dialog

100 Dono: Flávio Cunha

Page 105: Apostila Shell Flavio

AULA 9 − CGI em Shell

O Que é CGI

O CGI (Common Gateway Interface) é uma maneira de adicionar "inteligência" a páginas de Internet. CGIssão programas comuns que rodam no servidor onde a página se encontra. Sua função é processar algo emandar o resultado para a saída padrão. O servidor http (Apache) se encarrega de repassar este resultado aonavegador do usuário.

Programas do tipo CGI podem ser escritos em qualquer linguagem. Há apenas três requisitos para umprograma ser um CGI:

Ele deve estar no diretório correto (de CGIs)• Ele deve ser executável na linha de comando, pelo usuário do Apache• Ele deve mandar o resultado para a saída padrão (STDOUT)•

Com poucas modificações, qualquer script ou programa em Shell pode atuar como um CGI, gerando conteúdodinâmico para páginas de Internet. E com a ajuda das ferramentas do sistema, programas poderosos podemser feitos em parceria com páginas HTML.

O Primeiro CGI

Antes de tudo, para fazer CGIs o programador deve ter o servidor http corretamente configurado. Essaconfiguração foge ao escopo do curso, mas em resumo:

O módulo de CGI deve estar habilitado(LoadModule cgi_module /path/mod_cgi.so)

O diretório dos CGIs deve estar configurado(ScriptAlias /cgi−bin/ "/usr/lib/cgi−bin/")

A extensão .cgi ou .sh deve ser reconhecida como CGI(AddHandler cgi−script .cgi .sh)

Verifique qual é o usuário do Apache, geralmente "nobody" ou "www"(User nobody)

Apache configurado e rodando, tudo está pronto para o primeiro teste.

Primeiro requisito do CGI: Estar no diretório correto.

Então a primeira coisa antes de pensar em escrever um CGI, é ir para o diretório previamente configurado noApache para executar CGIs. Geralmente somente o usuário root pode escrever neste diretório. É aconselhávelcriar um subdiretório para "brincar" de CGI como usuário normal.

(normal)$ su − # vire root Password: (root )$ cd /usr/lib/cgi−bin/ (root )$ mkdir tst (root )$ chown usuario. tst (root )$ chmod 777 tst # dir público (root )$ logout (normal)$ cd /usr/lib/cgi−bin/

O CGI deve estar em /usr/lib/cgi−bin/tst/

Estando no diretório correto, crie um script simples, digamos oi.sh:

#!/bin/sh # oi.sh # 20030728 Aurelio Marinho Jargas

echo Content−type: text/plain echo echo oi

101 Dono: Flávio Cunha

Page 106: Apostila Shell Flavio

Segundo requisito do CGI: Ser executável pelo usuário do Apache.

Como o programa já tem a primeira linha mágica que chama o Shell, basta dar a permissão de execução paratodos os usuários nele:

$ chmod +x oi.sh

Não basta ser executável somente por você, lembre−se que é o usuário do Apache quem vai executar o CGI.Por isso CGIs dentro do $HOME não são uma boa idéia, pois somente seu usuário tem acesso a ele.

Então sempre, sempre que se criar um CGI, a primeira ação é torná−lo executável. A segunda ação, é ver seele funciona normalmente na linha de comando:

$ ./oi.sh Content−type: text/html

Oi

Ok, o programa é executável e não contém nenhum erro de sintaxe, está funcionando. Isso é muito importanteque se faça agora, antes de tentar acessar o CGI, pois na linha de comando é mais fácil resolver osproblemas do programa.

Para tirar qualquer dúvida se o usuário do Apache conseguirá ou não executar o CGI, acesse o sistema comoesse usuário e tente executar o programa:

(normal)$ su − Password: (root )$ su − nobody (nobody)$ cd /dir/do/cgi (nobody)$ ./oi.sh

O "nobody" deve conseguir executar o CGI

Se tudo estiver certo, a execução será normal. Caso contrário, resolva os problemas que aparecerem. Todaessa volta de se tornar root é necessária porque o usuário do Apache não possui senha nem Shell.

Terceiro requisito do CGI: Mandar o resultado para STDOUT.

Sim! O echo deu conta do recado e mandou o resultado para a tela. A primeira grande diferença que se nota,é que o CGI precisa mandar antes de tudo, a linha "Content−type: text/html" seguida de uma linha em branco.

O resultado deve sempre iniciar com "Content−type:...\n\n"

Isso é uma regra sagrada, um tabu que não pode ser quebrado. O Apache precisa receber essa linha antesde tudo, para identificar corretamente que os dados seguintes são parte de uma página HTML, e não umaimagem ou um arquivo compactado. Não pode haver linhas em branco ou espaços antes do "Content−type".

Testando o CGI

Agora basta abrir o navegador e acessar o CGI, para ver se funciona. O lynx, o navegador do modo texto éótimo para o período de testes, por ser rápido.

lynx http://localhost/cgi−bin/tst/oi.sh

O "localhost" é necessário para que a própria máquina seja usada como servidor das páginas, "cgi−bin" é odiretório raiz dos CGIs e o "tst" é o subdiretório criado para os testes. Se tudo correu bem, o texto "Oi"aparecerá na tela. Caso não tenha aparecido, procure por mensagens de erro nos logs do Apache, em/var/log/httpd/error_log

AULA 9 − CGI em Shell

102 Dono: Flávio Cunha

Page 107: Apostila Shell Flavio

Variáveis Especiais do Ambiente CGI

Há algumas variáveis especiais que são definidas no ambiente Shell que o Apache roda. Elas são acessíveispelos CGIs e podem ser utilizadas para obter informações do próprio servidor e também do cliente. Porexemplo:

DOCUMENT_ROOT Diretório raiz dos documentos HTML

HTTP_USER_AGENT Nome do navegador do cliente

QUERY_STRING Parâmetros de formulário (variáveis)

REMOTE_ADDR IP do cliente

REQUEST_METHOD Método requisitado (GET ou POST)

REQUEST_URI Página requisitada

SERVER_ADDR IP do servidor

SERVER_NAME Nome do servidor (Configurado no Apache)

Para ver quais são todas as variáveis do ambiente, basta fazer um CGI para mostrá−las:

#!/bin/sh # ambiente.cgi

echo Content−type: text/html echo echo "<h1>Ambiente CGI do servidor $SERVER_NAME</h1>" echo '<h2>Shell</h2>' sh −−version echo '<h2>Variáveis</h2>' echo '<pre>' set

Note que a extensão usada para este arquivo foi .cgi, e o anterior tinha sido .sh. Tanto faz contanto que adiretiva "AddHandler" na configuração do Apache suporte as duas extensões para CGI.

Note também como basta colocar as marcações HTML no meio do texto para que elas sejam interpretadas.Em particular o "<PRE>" é muito útil durante o período de desenvolvimento do programa e para Debug, paramanter as quebras de linha originais do texto.

Este é o básico do ambiente CGI. Conseguimos fazer com que um programa em Shell interaja com o Apachee atue como uma ferramenta de Internet. Os exemplos foram acessados localmente, mas os mesmosprogramas num servidor público, poderiam acessados por qualquer um no mundo! É a chance de fazerprogramas em Shell para uma grande audiência.

Utilizando Formulários

Mas um programa que sempre executa a mesma coisa é chato. Programas online geralmente envolvem teruma página HTML com um formulário onde o usuário preenche dados e o CGI é executado recebendo estesdados.

Primeiro Passo − Montar o Formulário

O formulário é uma página HTML normal. Está fora do escopo desse curso ensinar HTML, mas em resumoestes são os componentes mais utilizados em formulários:

AULA 9 − CGI em Shell

103 Dono: Flávio Cunha

Page 108: Apostila Shell Flavio

Componente Exemplo

Form <form method="POST" action="/cgi−bin/tst/arq.cgi"></form>

Submit <input type="submit" value="Enviar">

TextBox <input type="text" name="Idade" value="15" size="2">

TextArea <textarea name="notas" cols="40" rows="5">Texto</textarea>

CheckBox <input type="checkbox" name="item1" value="1" checked>Item 1

RadioBox <input type="radiobox" name="item1" value="1" checked>Item 1

Select <select name="itens"><option value="1">item 1</option></select>

E para acompanhar, um resumão de HTML:

Aqui está um arquivo HTML (não é um CGI!) com um formulário bem simples que pede o Nome, Idade e Sexodo usuário:

<!−− form.html − Exemplo simples de formulário −−>

<h1>Preencha seus Dados</h1>

<!−− Aqui começa o formulário −−> <form method="POST" action="/cgi−bin/tst/form.cgi">

<p>Nome: <input type="text" name="nome">

<p>Idade: <select name="idade"> <option value="18" >até 18 </option> <option value="18−30">entre 18 e 30</option> <option value="30" >mais de 30 </option> </select>

<!−− Note que o radiolist usa o mesmo "name" para ambos −−> <p>Sexo: <input type="radio" name="sexo" value="M"> Masculino <input type="radio" name="sexo" value="F"> Feminino

<!−− O botão de enviar −−> <p><input type="submit" value="Enviar!"> </form>

AULA 9 − CGI em Shell

104 Dono: Flávio Cunha

Page 109: Apostila Shell Flavio

Agora atenção! A página com o formulário não deve ficar junto com os CGIs. O apache guarda páginasseparadas dos programas. O diretório correto para as páginas é o indicado na variável de ambiente$DOCUMENT_ROOT.

Crie um subdiretório "tst" neste diretório e coloque o arquivo "form.html" ali. Feito isso, basta acessá−lo:

$ lynx http://localhost/tst/form.html

Em caso de erro no acesso, confira possíveis erros nas mensagens do navegador ou nos logs do Apache em/var/log/httpd/.

Segundo Passo − Enviar e Analisar o Formulário

Preencha livremente os campos do formulário e aperte o botão "Enviar". Aparecerá um erro pois ainda não foicriado o CGI do formulário, mas na própria página de erro aperte a tecla igual "=" para que o lynx mostredetalhes sobre o envio do formulário.

No meio das informações, há um campo muito importante chamado "Dados de postagem" (ou "Post data"):

Dados de postagem: nome=Aurelio+M.+Jargas&idade=18−30&sexo=M

Este é o formato no qual os dados preenchidos do formulário são "empacotados" e enviados ao CGI. É umalinha só, comprida, sem nenhum espaço em branco, chamada de tripa. Nesta tripa estão as definições devariáveis, separadas entre si pelo caractere "&". São elas:

nome=Aurelio+M.+Jargas idade=18−30 sexo=M

Note que o espaço em branco vira "+". Essa é a pedreira que o programador de CGI tem que enfrentar. Oprograma receberá esta tripa via entrada padrão e deve decifrá−la, extraindo os dados.

Terceiro Passo − Montar o CGI

Este é o CGI que recebe os dados do formulário, os extrai e mostra na tela:

#!/bin/sh # form.cgi − o CGI da página form.html

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− HTML inicial echo Content−type: text/html echo echo '<h1>Os dados enviados foram:</h1>' echo '<pre>' #−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−

read TRIPA # lê dados STDIN

AULA 9 − CGI em Shell

105 Dono: Flávio Cunha

Page 110: Apostila Shell Flavio

TRIPA=`echo $TRIPA | tr + ' '` # restaura espaços

IFS='&' ; set − $TRIPA # separa dados while [ "$1" ]; do # p/cada nome=valor varnome=` echo $1 | cut −d= −f1` varvalor=`echo $1 | cut −d= −f2` eval $varnome=\"$varvalor\" # grava variável shift done

#−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− echo Nome : $nome echo Idade: $idade echo Sexo : $sexo

Este é um exemplo bem simples, e que não está levando em conta algo muito importante: o mascaramento desímbolos e letras acentuadas.

No "empacotamento" dos dados do formulário, somente as letras, números e alguns poucos símbolos sãopassados limpos, como são. Todos os outros caracteres são mascarados para o formato %HH, onde HH é ocódigo do caractere na tabela ASCII, em hexadecimal.

No CGI é preciso decodificar estes caracteres. Um simples echo −e \xHH serve para decodificar cadacaractere, mas como este processo envolve várias "pegadinhas", é melhor utilizar uma ferramentaespecialista, o "urldecode" (http://www.shelldorado.com/scripts/cmds/urldecode).

Colocando esta ferramenta no mesmo diretório dos CGIs, ou num diretório que faz parte do PATH do sistema,basta alterar a linha que extrai o valor de cada variável para utilizá−lo:

varvalor=`echo $1 | cut −d= −f2 | urldecode`

Depurando CGIs

Todas as dicas já vistas de como depurar programas em Shell são aplicáveis aos CGIs também, a diferença éque todas as informações de depuração também serão enviadas ao navegador do cliente.

Basta colocar os echos estratégicos ou usar a função Debug(). Mas para a depuração com o −x, tem umapegadinha. As mensagens de debug são enviadas para a saída de erro, e não a STDOUT.

Onde Estão as Mensagens de Erro?

O Apache só lê a STDOUT, e manda todas as mensagens de erro para o arquivo/var/log/httpd/error_log. Isso significa que seu CGI até poderia ter comandos inválidos, mas como oserros estavam indo para um arquivo, passavam despercebidos.

A solução é conectar a saída de erro com a saída padrão, de maneira que o Apache envie ambas ao cliente.Para isso, basta colocar logo no início do CGI, a seguinte linha:

exec 2>&1

E pronto. Tanto STDERR quanto STDOUT serão mandadas ao navegador.

ATENÇÃO: Não use a depuração do arquivo todo, com o #!/bin/sh −x. Assim, as mensagens de debugaparecerão antes do "Content−type:..." e o CGI ficará quebrado.

Ao invés, use o Debug do tipo liga/desliga, com o set −x, +x. Juntando tudo, este é o "início padrão" dequalquer CGI em Shell:

#!/bin/sh # nome.cgi − descrição #...cabeçalho...

exec 2>&1 # liga msgs de erro

echo Content−type: text/html

AULA 9 − CGI em Shell

106 Dono: Flávio Cunha

Page 111: Apostila Shell Flavio

echo

# set −x # liga/desliga Debug

read TRIPA # recebe os dados

Testando CGIs na Linha de Comando

Outra maneira prática de testar CGIs é usar a própria linha de comando, sem precisar de Apache, navegador,preencher formulários, nada disso.

Como o CGI recebe os dados da entrada padrão, e o formato desses dados é conhecido (a TRIPA), bastaalimentar o CGI com uma tripa falsa e esperar ele mandar o resultado para a tela. Simples assim.

$ echo 'nome=Joaozinho+Silva&idade=55&sexo=M' | ./form.cgi Content−type: text/html

<h1>Os dados enviados foram:</h1> <pre> Nome : Joaozinho Silva Idade: 55 Sexo : M

Ou ainda, caso o ambiente especial do Apache seja necessário, ainda assim é possível alimentar o CGI comuma tripa falsa, na linha de comando.

O navegador lynx possui uma opção chamada −post−data, que serve justamente para enviar dados a umCGI. Ela recebe a tripa pela entrada padrão e a envia ao Apache, como se aqueles dados tivessem sidopreenchidos num formulário. Usa−se também a opção −dump para que a página resultante seja mandadapara a tela:

$ echo 'nome=Joaozinho+Silva&idade=55&sexo=M' | lynx −post−data −dump http://localhost/cgi−bin/tst/form.cgi

Os dados enviados foram:

Nome : Joaozinho Silva Idade: 55 Sexo : M

Note que o lynx já renderizou o HTML e veio somente o conteúdo da página. Caso deseje ver o código HTMLtambém, basta trocar a opção −dump pela −source.

−o−

TAREFA EM AULA:

Fazer um CGI completo e funcional, onde o usuário preenche um formulário e recebe uma resposta de voltano navegador.

AULA 9 − CGI em Shell

107 Dono: Flávio Cunha

Page 112: Apostila Shell Flavio

AULA 10 − Apresentação dos Programas dos Alunos

Programa do Aluno

Aprendizado sem prática e experiência pessoal é descartável.

A última aula é a chance do aluno praticar tudo aquilo que aprendeu durante o curso, fixar os conceitos econhecer as "pegadinhas" que só quem "põe a mão na massa" conhece.

São três horas de programação intensiva, com o acompanhamento direto do professor, para codificar umprograma em Shell, de tema livre, a escolha do aluno.

Ao final da aula, cada aluno apresentará o seu programa, comentando sobre as dificuldades encontradas esobre as características da sua obra.

Durante o curso, foram vistos vários conceitos como opções de linha de comando, uso das ferramentas,caracteres de controle, arquivo de configuração, interface com o Dialog, Banco de Dados, ExpressõesRegulares e CGI.

Usando um ou mais desses conceitos, o aluno conseguirá fazer um programa completo. Quanto mais dessesconceitos forem aplicados, mais profissional será o programa.

Todos os alunos, independente do nível de conhecimento em Shell terão condições de fazer um programa.Não é preciso temer ou encarar essa tarefa como um teste. Não é uma prova, é a prática. Não há programascertos ou errados, há o fruto de um trabalho que deve ser reconhecido.

E acima de tudo: Programar tem que ser divertido!

108 Dono: Flávio Cunha

Page 113: Apostila Shell Flavio

Mensagem FinalEste curso não forma programadores, mas "abre os olhos" dos alunos para as possibilidadesda programação em Shell. Durante as aulas, as técnicas são aprendidas e praticadas, massomente a codificação exaustiva pós−curso tornará um "scripteiro" em um programador.

Se ao sair deste curso o aluno não criar o hábito de programar sempre, infelizmente terá sidoum desperdício de tempo ter assistido às aulas. Experiência não se adquire lendo ou ouvindo,é preciso ação.

Um diploma não significa nada na área dos códigos. Um programador "se forma" sozinho,fazendo uma única tarefa incansavelmente: programar. Seu currículo é os seus programas.Quanto mais se codifica, mais se aprende.

Caso o aluno já seja um programador, as palavras anteriores com certeza não são novidade.Caso o aluno tenha entrado no curso como um interessado em Shell, ou mesmo um scripteiroexperiente, eu espero que as aulas tenham despertado um desejo IMENSO de sairprogramando. Espero que neste momento sua cabeça esteja cheia de idéias, cheia deprogramas que você vai codificar assim que chegar em casa.

Para mim, será um grande prazer saber que cada um dos alunos que saiu daqui, se tornouum programador Shell. Seja um programador hobbista, profissional, instrutor, guru, ousimplesmente: um programador. O cara que simplesmente adora programar, que inventaproblemas só para ter o prazer de fazer um programa para resolvê−los.

Na minha página na Internet há mais informações sobre Shell e assuntos relacionados:http://aurelio.net

Lá também está o pacote com todos os arquivos de exemplo utilizados na apostila, para nãoprecisar redigitar: http://aurelio.net/shell/apostila/pacotao.tgz

Alunos, amigos. Deixo um grande abraço. Mantenham contato!

Aurélio Marinho Jargas ([email protected])

109 Dono: Flávio Cunha

Page 114: Apostila Shell Flavio

Direitos Autorais e Permissão de CópiaEsta apostila entitulada CURSO PROGRAMAÇÃO PROFISSIONAL EM SHELL é uma obra registrada noEscritório de Direitos Autorais da Biblioteca Nacional em Novembro de 2003, sob o número 303.593, livro 552,folha 253 em nome de AURÉLIO MARINHO JARGAS, adiante referenciado como AUTOR.

Este exemplar digital em formato PDF é de propriedade exclusiva de FLÁVIO CUNHA, adiante referenciadocomo PROPRIETÁRIO.

É permitido ao PROPRIETÁRIO fazer múltiplas cópias deste arquivo PDF, para uso pessoal e particular.

É permitido ao PROPRIETÁRIO fazer a impressão em papel, parcial ou integral, sem limite de número decópias, para uso pessoal e particular.

É permitido ao PROPRIETÁRIO citar trechos do material em canais públicos como e−mail e páginas deInternet, desde que o trecho não ultrapasse 300 palavras e a autoria seja também citada, com o nomecompleto do AUTOR e o endereço de seu site: http://aurelio.net.

É proibida a reprodução pública desta obra, como disponibilizá−la para download na Internet, enviá−la pore−mail a terceiros, trocá−la por outros arquivos em sistemas P2P e outros.

É proibida a conversão deste documento PDF para outros formatos digitais como HTML, RTF, e TXT. Nocaso do PROPRIETÁRIO ter necessidades especiais em que o formato PDF seja ilegível, favor contactar oAUTOR.

É repudiado e proibido o uso deste material para fins lucrativos, como revenda ou uso em cursos etreinametos pagos, sem prévia autorização, por escrito, do autor.

Resumindo, este PDF é exclusivo do PROPRIETÁRIO para uso particular.

Apostila CURSO PROGRAMAÇÃO PROFISSIONAL EM SHELL Copyright© 2003, 2004 por Aurélio Marinho Jargas Nº Registro na BN: 303.593 Livro: 552 Folha: 253

110 Dono: Flávio Cunha