Curso de ShellScript - Lm09 shellscript9

download Curso de ShellScript - Lm09 shellscript9

If you can't read please download the document

Transcript of Curso de ShellScript - Lm09 shellscript9

1. T bom, j sei que voc vai querer chope antes de comear, mas t to a m de te mostrar o que z que j vou pedir a rodada enquanto isso. A Chico, manda dois! O dele sem colarinho pra no deixar cheiro ruim nesse bigodo Enquanto o chope no chega, deixa eu te lembrar o que voc me pediu na edio passada: era para refazer o programa listartista com a tela formatada e exe- cuo em loop, de forma que ele s termine quando receber um [ENTER] sozinho como nome do artista. Eventuais mensagens de erro e perguntas feitas ao usurio deveriam ser mostradas na antepenltima linha da tela, utilizando para isso as rotinas externas mandamsg.func e pergunta.func que desenvolvemos durante nosso papo na edio passada. Primeiramente eu dei uma encolhida nas rotinas mandamsg.func e pergunta.func, que caram como na listagem 1. E na listagem 2 voc tem o grando, nossa verso refeita do listaartista. Puxa, voc chegou com a corda toda! Gostei da forma como voc resolveu o problema e estruturou o programa. Foi mais trabalhoso, mas a apresenta- o cou muito legal e voc explorou bastante as opes do comando tput. Vamos testar o resultado com um lbum do Emerson, Lake & Palmer que tenho cadastrado. Envenenando a escrita Ufa! Agora voc j sabe tudo sobre leitura de dados, mas quanto escrita ainda est apenas engatinhando. J sei que voc vai me perguntar: Ora, no com o comando echo e com os redirecionamentos de sada que se escreve dados?. Bom, a resposta "mais ou menos". Com estes comandos voc escreve 90% do que precisa, porm se precisar escrever algo formatado eles lhe daro muito trabalho. Para formatar a sada veremos agora uma instruo muito mais interessante, a printf. Sua sintaxe a seguinte: Hoje vamos aprender mais sobre formatao de cadeias de caracteres, conhecer as principais variveis do Shell e nos aventurar no (ainda) desconhecido territrio da expanso de parmetros. E d-lhe chope! por Jlio Cezar Neves Curso de Shell Script Papo de BotequimParte IX DaveHamilton-www.sxc.hu Listagem 1: mandamsg.func e pergunta.func mandamsg.func 01 # A funo recebe somente um parmetro 02 # com a mensagem que se deseja exibir. 03 # Para no obrigar o programador a passar 04 # a msg entre aspas, usaremos $* (todos 05 # os parmetro, lembra?) e no $1. 06 Msg="$*" 07 TamMsg=${#Msg} 08 Col=$(((TotCols - TamMsg) / 2)) # Centra msg na linha 09 tput cup $LinhaMesg $Col 10 read -n1 -p "$Msg " pergunta.func 01 # A funo recebe 3 parmetros na seguinte ordem: 02 # $1 - Mensagem a ser mostrada na tela 03 # $2 - Valor a ser aceito com resposta padro 04 # $3 - O outro valor aceito 05 # Supondo que $1=Aceita?, $2=s e $3=n, a linha 06 # abaixo colocaria em Msg o valor "Aceita? (S/n)" 07 Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)" 08 TamMsg=${#Msg} 09 Col=$(((TotCols - TamMsg) / 2)) # Centraliza msg na linha 10 tput cup $LinhaMesg $Col 11 read -n1 -p "$Msg " SN 12 [ ! $SN ] && SN=$2 # Se vazia coloca default em SN 13 SN=$(echo $SN | tr A-Z a-z) # A sada de SN ser em minscula 14 tput cup $LinhaMesg $Col; tput el # Apaga msg da tela Linux User 84 Papo de Botequim www.linuxmagazine.com.br junho 2005 edio09 2. printf formato [argumento...] Onde formato uma cadeia de caracteres que contm trs tipos de objeto: caracteres simples, caracteres para es- pecicao de formato (ou de controle) e seqncia de esca- pe no padro da linguagem C. argumento a cadeia de caracteres a ser impressa sob o controle de formato. Cada um dos caracteres uti- lizados precedido pelo ca- racter % e, logo a seguir, vem a especicao de formato de acordo com a tabela 1. As seqncias de escape padro da linguagem C so sempre precedidas pelo ca- ractere contra-barra (). As reconhecidas pelo comando printf so as da tabela 2. No acaba por a no! Tem muito mais coisa sobre essa instruo, mas como esse um assunto muito cheio de detalhes e, portanto, chato para explicar e pior ainda para ler ou estudar, vamos passar direto aos exemplos com co- mentrios. Veja s: $ printf "%c" "1 caracter" 1$ Errado! S listou 1 caractere e no saltou linha ao nal $ printf "%cn" "1 caracter" 1 Saltou linha mas ainda no listou a cadeia inteira $ printf "%c caracteren" 1 1 caractere Listagem 2: listaartista $ cat listartista3.sh 01 #!/bin/bash 02 # Dado um artista, mostra as suas musicas 03 # versao 3 04 LinhaMesg=$((`tput lines` - 3)) # Linha onde as msgs sero mostradas 05 TotCols=$(tput cols) # Qtd de colunas na tela para enquadrar msgs 06 clear 07 echo " +-----------------------------------+ | Lista Todas as Msicas de um Determinado Artista | | ===== ===== == ======= == == =========== ======= | | | | Informe o Artista: | +-----------------------------------+" 08 while true 09 do 10 tput cup 5 51; tput ech 31 # ech=Erase chars (31 para no apagar barra vertical) 11 read Nome 12 if [ ! "$Nome" ] # $Nome esta vazio? 13 then 14 . pergunta.func "Deseja Sair?" s n 15 [ $SN = n ] && continue 16 break 17 fi 18 fgrep -iq "^$Nome~" musicas || # fgrep no interpreta ^ como expresso regular 19 { 20 . mandamsg.func "No existe msica desse artista" 21 continue 22 } 23 tput cup 7 29; echo '| |' 24 LinAtual=8 25 IFS=" 26 :" 27 for ArtMus in $(cut -f2 -d^ musicas) # Exclui nome do album 28 do 29 if echo "$ArtMus" | grep -iq "^$Nome~" 30 then 31 tput cup $LinAtual 29 32 echo -n '| " 33 echo $ArtMus | cut -f2 -d~ 34 tput cup $LinAtual 82 35 echo '|' 36 let LinAtual++ 37 if [ $LinAtual -eq $LinhaMesg ] 38 then 39 . mandamsg.func "Tecle Algo para Continuar..." 40 tput cup 7 0; tput ed # Apaga a tela a partir da linha 7 41 tput cup 7 29; echo '| |' 42 LinAtual=8 43 fi 44 fi 45 done 46 tput cup $LinAtual 29; echo '| |' 47 tput cup $((++LinAtual)) 29 48 read -n1 -p "+--Tecle Algo para Nova Consulta+" 49 tput cup 7 0; tput ed # Apaga a tela a partir da linha 7 50 done www.linuxmagazine.com.br junho 2005 edio09 85 Papo de Botequim Linux User 3. Opa, essa a forma correta! O %c rece- beu o valor 1, como queramos: $ a=2 $ printf "%c caracteresn" $a 2 caracteres O %c recebeu o valor da varivel $a. $ printf "%10c caracteresn" $a 2 caracteres $ printf "%10cn" $a caracteres 2 c Repare que, nos dois ltimos exemplos, em virtude do uso do %c, s foi listado um caractere de cada cadeia de caracteres passada como parmetro. O valor 10 frente do c no signica 10 caracteres. Um nmero seguindo o sinal de percentagem (%) signica o tamanho que a cadeia ter aps a execuo do comando. Vamos ver a seguir mais alguns exemplos. Os co- mandos abaixo: $ printf "%dn" 32 32 $ printf "%10dn" 32 32 preenchem a string com espaos em branco esquerda (oito espaos mais dois caracteres, 10 dgitos), no com zeros. J no comando abaixo: $ printf "%04dn" 32 0032 O 04 aps % signica formate a string em quatro dgitos, com zeros esquerda se necessrio. No comando: $ printf "%en" $(echo "scale=2 ; 100/6" | bc) 1.666000e+01 O padro do %e seis casas decimais. J no comando: $ printf "%.2en" `echo "scale=2 ; 100/6" | bc` 1.67e+01 O .2 especicou duas casas decimais. Observe agora: $ printf "%fn" 32.3 32.300000 O padro do %f seis casas decimais. E no comando: $ printf "%.2fn" 32.3 32.30 O .2 especicou duas casas decimais. Agora observe: $ printf "%.3fn" `echo "scale=2 ; 100/6" | bc` 33.330 O bc devolveu duas casas decimais e o printf colocou o zero direita. O co- mando a seguir: $ printf "%on" 10 12 Converteu o valor 10 para base octal. Para melhorar experimente: $ printf "%03on" 27 033 Assim a converso ca com mais jeito de octal, n?. O que este aqui faz? $ printf "%sn" Peteleca Peteleca $ printf "%15sn" Peteleca Peteleca Imprime Peteleca com 15 caracteres. A cadeia de caracteres preenchida com espaos em branco esquerda. J no co- mando: $ printf "%-15sNevesn" Peteleca Peteleca Neves O menos (-) colocou espaos em branco direita de Peteleca at completar os 15 caracteres pedidos. E o comando abaixo, o que faz? $ printf "%.3sn" Peteleca Pet O .3 manda truncar a cadeia de ca- racteres aps as trs primeiras letras. E o comando a seguir: $ printf "%10.3san" Peteleca Peta Pet Imprime a cadeia com 10 caracteres, truncada aps os trs primeiros, conca- tenada com o caractere a (aps o s). E esse comando a seguir, o que faz? Tabela 1: Formatos de caractere Caractere A expresso ser impressa como: c Caractere simples d Nmero no sistema decimal e Notao cientca exponencial f Nmero com ponto decimal (oat) g O menor entre os formatos %e e %f com omisso dos zeros no signicativos o Nmero no sistema octal s Cadeia de caracteres x Nmero no sistema hexadecimal % Imprime um %. No h nenhum tipo de converso Tabela 2: Seqncias de escape Seqncia Efeito a Soa o beep b Volta uma posio (backspace) f Salta para a prxima pgina lgica (form feed) n Salta para o incio da linha se- guinte (line feed) r Volta para o incio da linha cor- rente (carriage return) t Avana para a prxima marca de tabulao Linux User 86 Papo de Botequim www.linuxmagazine.com.br junho 2005 edio09 4. $ printf EXEMPLO %xn 45232 EXEMPLO b0b0 Ele transformou o nmero 45232 para hexadecimal (b0b0), mas os zeros no combinam com o resto. Experimente: $ printf EXEMPLO %Xn 45232 EXEMPLO B0B0 Assim disfarou melhor! (repare no X maisculo). Pra terminar, que tal o co- mando abaixo: $ printf %X %XL%Xn 49354 192 10 C0CA C0LA Este a no marketing e bastante completo, veja s como funciona: O primeiro %X converteu 49354 em he- xadecimal, resultando em C0CA (leia-se c, zero, c e a). Em seguida veio um espao em branco seguido por outro %XL. O %X converteu o 192 dando como resultado C0 que com o L fez C0L. E nal- mente o ltimo parmetro %X transformou o nmero 10 na letra A. Conforme vocs podem notar, a instru- o bastante completa e complexa. Ain- da bem que o echo resolve quase tudo... Acertei em cheio quando resolvi expli- car o printf atravs de exemplos, pois no saberia como enumerar tantas regri- nhas sem tornar a leitura enfadonha. Principais variveis do Shell O Bash possui diversas variveis que servem para dar informaes sobre o ambiente ou alter-lo. So muitas e no pretendo mostrar todas elas, mas uma pequena parte pode lhe ajudar na elaborao de scripts. Veja a seguir as principais delas: CDPATH Contm os caminhos que sero pesquisados para tentar localizar um diretrio especicado. Apesar dessa varivel ser pouco conhecida, seu uso deve ser incentivado por poupar muito trabalho, principalmente em instalaes com estrutura de diretrios em mltiplos nveis. Veja o exemplo a seguir: $ echo $CDPATH .:..:~:/usr/local $ pwd /home/jneves/LM $ cd bin $ pwd /usr/local/bin Como /usr/local estava na minha varivel $CDPATH e no existia o diretrio bin em nenhum dos seus antecessores (., .. e ~), o comando cd foi executado tendo como destino /usr/local/bin. HISTSIZE Limita o nmero de ins- trues que cabem dentro do arquivo de histrico de comandos (normalmente .bash_history, mas na verdade o que est indicado na varivel $HISTFILE). Seu valor padro 500. HOSTNAME O nome do host corrente (que tambm pode ser obtido com o co- mando uname -n). LANG Usada para determinar o idioma falado no pas (mais especicamente ca- tegoria do locale). Veja um exemplo: $ date Thu Apr 14 11:54:13 BRT 2005 $ LANG=pt_BR date Qui Abr 14 11:55:14 BRT 2005 LINENO O nmero da linha do script ou funo que est sendo executada. Seu uso principal mostrar mensagens de erro juntamente com as variveis $0 (nome do programa) e $FUNCNAME (nome da funo em execuo). LOGNAME Esta varivel armazena o nome de login do usurio . MAILCHECK Especica, em segundos, a freqncia com que o Shell verica a pre- sena de correspondncia nos arquivos indicados pela variveis $MAILPATH ou $MAIL. O tempo padro de 60 segundos (1 minuto). A cada intervalo o Shell far a vericao antes de exibir o prximo prompt primrio ($PS1). Se essa varivel estiver sem valor ou com um valor menor ou igual a zero, a busca por novas men- sagens no ser efetuada. PATH Caminhos que sero pesquisa- dos para tentar localizar um arquivo espe- cicado. Como cada script um arquivo, caso use o diretrio corrente (.) na sua varivel $PATH, voc no necessitar usar o comando ./scrp para que o script scrp seja executado. Basta digitar scrp. Este o modo que prero. PIPESTATUS uma varivel do tipo vetor (array) que contm uma lista de valores de cdigos de retorno do ltimo pipeline executado, isto , um array que abriga cada um dos $? de cada instruo do ltimo pipeline. Para entender melhor, veja o exemplo a seguir: $ who jneves pts/0 Apr 11 16:26 (10.2.4.144) jneves pts/1 Apr 12 12:04 (10.2.4.144) $ who | grep ^botelho $ echo ${PIPESTATUS[*]} 0 1 Neste exemplo mostramos que o usu- rio botelho no estava logado, em seguida executamos um pipeline que procurava por ele. Usa-se a notao [*] em um array para listar todos os seus elementos; dessa forma, vimos que a pri- meira instruo (who) foi bem-sucedida (cdigo de retorno 0) e a seguinte (grep) no (cdigo de retorno 1). PROMPT_COMMAND Se esta varivel re- ceber o nome de um comando, toda vez que voc teclar um [ENTER] sozinho no prompt principal ($PS1), esse comando ser executado. muito til quando voc precisa repetindo constantemente uma determinada instruo. PS1 o prompt principal. No Papo de Botequim usamos os padres $ para usurio comum e # para root, mas mui- www.linuxmagazine.com.br junho 2005 edio09 87 Papo de Botequim Linux User 5. to freqente que ele esteja personalizado. Uma curiosidade que existe at concurso de quem programa o $PS1 mais criativo. PS2 Tambm chamado prompt de continuao, aquele sinal de maior (>) que aparece aps um [ENTER] sem o comando ter sido encerrado. PWD Possui o caminho completo ($PATH) do diretrio corrente. Tem o mesmo efeito do comando pwd. RANDOM Cada vez que esta varivel acessada, devolve um inteiro aleatrio en- tre 0 e 32767. Para gerar um inteiro entre 0 e 100, por exemplo, digitamos: $ echo $((RANDOM%101)) 73 Ou seja, pegamos o resto da diviso do nmero randmico gerado por 101 porque o resto da diviso de qualquer nmero por 101 varia entre 0 e 100. REPLY Use esta varivel para recuperar o ltimo campo lido, caso ele no tenha nenhuma varivel associada. Exemplo: $ read -p "Digite S ou N: " Digite S ou N: N $ echo $REPLY N SECONDS Esta varivel informa, em se- gundos, h quanto tempo o Shell corrente est de p. Use-a para demonstrar a estabilidade do Linux e esnobar usurios daquela coisa com janelinhas coloridas que chamam de sistema operacional, mas que necessita de reboots freqentes. TMOUT Se esta varivel contiver um valor maior do que zero, esse valor ser considerado o timeout padro do comando read. No prompt, esse valor interpretado como o tempo de espera por uma ao antes de expirar a sesso. Supondo que a varivel contenha o valor 30, o Shell encerrar a sesso do usurio (ou seja, far logout) aps 30 segundos sem nenhuma ao no prompt. Expanso de parmetros Bem, muito do que vimos at agora so comandos externos ao Shell. Eles quebram o maior galho, facilitam a visualizao, manuteno e depurao do cdigo, mas no so to ecientes quanto os intrnse- cos (built-ins). Quando o nosso problema for performance, devemos dar preferncia ao uso dos intrnsecos. A partir de agora vou te mostrar algumas tcnicas para o seu programa pisar no acelerador. Na tabela 3 e nos exemplos a seguir, veremos uma srie de construes cha- madas expanso (ou substituio) de parmetros (Parameter Expansion), que substituem instrues como o cut, o expr, o tr, o sed e outras de forma mais gil. Vamos ver alguns exemplos: se em uma pergunta o S oferecido como valor de- fault (padro) e a sada vai para a varivel SN, aps ler o valor podemos fazer: SN=$(SN:-S} Para saber o tamanho de uma cadeia: $ cadeia=0123 $ echo ${#cadeia} 4 Para extrair dados de cadeia, da posi- o um at o nal fazemos: $ cadeia=abcdef $ echo ${cadeia:1} bcdef Repare que a origem zero e no um. Vamos extrair 3 caracteres a partir da 2 posio da mesma varivel cadeia: $ echo ${cadeia:2:3} cde Repare que novamente a origem da con- tagem zero e no um. Para suprimir tudo esquerda da primeira ocorrncia de uma cadeia, faa: $ cadeia="Papo de Botequim" $ echo ${cadeia#*' '} de Botequim $ echo "Conversa "${cadeia#*' '} Conversa de Botequim No exemplo anterior foi suprimido esquerda tudo o que casa com a menor ocorrncia da expresso * , ou seja, todos os caracteres at o primeiro espao em branco. Esses exemplos tambm po- deriam ser escritos sem proteger o espao da interpretao do Shell (mas prero proteg-lo para facilitar a legibilidade do cdigo). Veja s: $ echo ${cadeia#* } de Botequim $ echo "Conversa "${cadeia#* } Conversa de Botequim Repare que na construo de expr permitido o uso de metacaracteres. Utilizando o mesmo valor da varivel cadeia, observe como faramos para ter somente Botequim: $ echo ${cadeia##*' '} Botequim $ echo "Vamos 'Chopear' no "${cadeia##*' '} Vamos 'Chopear' no Botequim Desta vez suprimimos esquerda de cadeia a maior ocorrncia da expresso expr. Assim como no caso anterior, o uso de metacaracteres permitido. Outro exemplo mais til: para que no aparea o caminho (path) completo do seu programa ($0) em uma mensagem de erro, inicie o seu texto da seguinte forma: echo Uso: ${0##*/} texto da mensagem de erro Neste exemplo seria suprimido es- querda tudo at a ltima barra (/) do caminho, restando somente o nome do programa. O caractere % simtrico ao #, veja o exemplo: Linux User 88 Papo de Botequim www.linuxmagazine.com.br junho 2005 edio09 6. $ echo $cadeia Papo de Botequim $ echo ${cadeia%' '*} Papo de $ echo ${cadeia%%' '*} Papo Para trocar primeira ocorrncia de uma subcadeia em uma cadeia por outra: $ echo $cadeia Papo de Botequim $ echo ${cadeia/de/no} Papo no Botequim $ echo ${cadeia/de /} Papo Botequim Preste ateno quando for usar metaca- racteres! Eles so gulosos e sempre com- binaro com a maior possibilidade; No exemplo a seguir eu queria trocar Papo de Botequim por Conversa de Botequim: $ echo $cadeia Papo de Botequim $ echo ${cadeia/*o/Conversa} Conversatequim A idia era pegar tudo at o primeiro o, mas acabou sendo trocado tudo at o ltimo o. Isto poderia ser resolvido de diversas maneiras. Eis algumas: $ echo ${cadeia/*po/Conversa} Conversa de Botequim $ echo ${cadeia/????/Conversa} Conversa de Botequim Trocando todas as ocorrncias de uma subcadeia por outra. O comando: $ echo ${cadeia//o/a} Papa de Batequim Ordena a troca de todos as letras o por a. Outro exemplo mais til para contar a quantidade de arquivos existentes no diretrio corrente. Observe o exemplo: $ ls | wc -l 30 O wc pe um monte de espaos em branco antes do resultado. Para tir-los: # QtdArqs recebe a sada do comando $ QtdArqs=$(ls | wc -l) $ echo ${QtdArqs/ * /} 30 Nesse exemplo, eu sabia que a sada era composta de brancos e nmeros, por isso montei essa expresso para trocar todos os espaos por nada. Note que antes e aps o asterisco (*) h espaos em branco. H vrias formas de trocar uma subca- deia no incio ou no m de uma varivel. Para trocar no incio fazemos: $ echo $Passaro quero quero $ echo Como diz o sulista - ${PassaroU /#quero/no} Como diz o sulista - no quero Para trocar no nal fazemos: $ echo Como diz o nordestino - U ${Passaro/%quero/no} Como diz o nordestino - quero no Agora j chega, o papo hoje foi chato porque teve muita decoreba, mas o que mais importa voc ter entendido o que te falei. Quando precisar, consulte estes guardanapos onde rabisquei as dicas e depois guarde-os para consultas futuras. Mas voltando vaca fria: t na hora de tomar outro e ver o jogo do Mengo. Pra prxima vez vou te dar moleza e s vou cobrar o seguinte: pe- gue a rotina pergunta.func (da qual falamos no incio do nosso bate-papo de hoje, veja a listagem 1) e otimize-a para que a varivel $SN receba o valor padro por expanso de parmetros, como vimos. E no se esquea: em caso de dvidas ou falta de companhia para um (ou mais) chope s mandar um e-mail para julio. [email protected]. E diga para os amigos que quem estiver a m de fazer um curso porreta de programao em Shell deve mandar um e-mail para julio.neves@tecnohall. com.br para informar-se. Valeu! Tabela 3: Tipos de expanso de parmetros Expanso de parmetros Resultado esperado ${var:-padrao} Se var vazia, o resultado da expresso padro ${#cadeia} Tamanho de $cadeia ${cadeia:posicao} Extrai uma subcadeia de $cadeia a partir de posio. Origem zero ${cadeia:posicao:tamanho} Extrai uma subcadeia de $cadeia a partir de posio com tamanho igual a tamanho. Origem zero ${cadeia#expr} Corta a menor ocorrncia de $cadeia esquerda da expresso expr ${cadeia##expr} Corta a maior ocorrncia de $cadeia esquerda da expresso expr ${cadeia%expr} Corta a menor ocorrncia de $cadeia direita da expresso expr ${cadeia%%expr} Corta a maior ocorrncia de $cadeia direita da expresso expr ${cadeia/subcad1/subcad2} Troca a primeira ocorrncia de subcad1 por subcad2 ${cadeia//subcad1/subcad2} Troca todas as ocorrncias de subcad1 por subcad2 ${cadeia/#subcad1/subcad2} Se subcad1 combina com o incio de cadeia, ento trocado por subcad2 ${cadeia/%subcad1/subcad2} Se subcad1 combina com o m de cadeia, ento trocado por subcad2 Sobreoautor Julio Cezar Neves Analista de Suporte de Sistemas desde 1969 e trabalha com Unix desde 1980, quando participou do desen- volvimento do SOX, um sistema operacio- nal similar ao Unix produzido pela Cobra Computadores. Pode ser contatado no e-mail [email protected] www.linuxmagazine.com.br junho 2005 edio09 89 Papo de Botequim Linux User