Curso de Shell Script 09/11

264 views
197 views

Published on

Hoje vamos aprender mais sobre formatação de cadeias de caracteres, conhecer as principais variáveis do Shell e nos aventurar no (ainda) desconhecido território da expansão de parâmetros. E dá-lhe chope!

Published in: Technology
0 Comments
0 Likes
Statistics
Notes
  • Be the first to comment

  • Be the first to like this

No Downloads
Views
Total views
264
On SlideShare
0
From Embeds
0
Number of Embeds
7
Actions
Shares
0
Downloads
8
Comments
0
Likes
0
Embeds 0
No embeds

No notes for slide

Curso de Shell Script 09/11

  1. 1. Linux User Papo de Botequim Papo de Botequim Curso de Shell Script Parte IX Dave Hamilton - www.sxc.hu Hoje vamos aprender mais sobre formatação de cadeias de caracteres, conhecer as principais variáveis do Shell e nos aventurar no (ainda) desconhecido território da expansão de parâmetros. E dá-lhe chope! por Júlio Cezar Neves T á bom, já sei que você vai querer chope antes de começar, Bom, a resposta é "mais ou menos". Com estes comandos mas tô tão a fi m de te mostrar o que fi z que já vou pedir a você escreve 90% do que precisa, porém se precisar escrever rodada enquanto isso. Aê Chico, manda dois! O dele é sem algo formatado eles lhe darão muito trabalho. Para formatar a colarinho pra não deixar cheiro ruim nesse bigodão… saída veremos agora uma instrução muito mais interessante, Enquanto o chope não chega, deixa eu te lembrar o que a printf. Sua sintaxe é a seguinte: você me pediu na edição passada: era para refazer o programa listartista com a tela formatada e exe- Listagem 1: mandamsg.func e pergunta.func cução em loop, de forma que ele só termine quando mandamsg.func receber um [ENTER] sozinho como nome do artista. 01 # A função recebe somente um parâmetro Eventuais mensagens de erro e perguntas feitas ao 02 # com a mensagem que se deseja exibir. usuário deveriam ser mostradas na antepenúltima 03 # Para não obrigar o programador a passar linha da tela, utilizando para isso as rotinas externas 04 # a msg entre aspas, usaremos $* (todos mandamsg.func e pergunta.func que desenvolvemos 05 # os parâmetro, lembra?) e não $1. 06 Msg="$*" durante nosso papo na edição passada. 07 TamMsg=${#Msg} Primeiramente eu dei uma encolhida nas rotinas 08 Col=$(((TotCols - TamMsg) / 2)) # Centra msg na linha mandamsg.func e pergunta.func, que ficaram como 09 tput cup $LinhaMesg $Col na listagem 1. E na listagem 2 você tem o “grandão”, 10 read -n1 -p "$Msg " nossa versão refeita do listaartista. – Puxa, você chegou com a corda toda! Gostei da pergunta.func forma como você resolveu o problema e estruturou 01 # A função recebe 3 parâmetros na seguinte ordem: 02 # $1 - Mensagem a ser mostrada na tela o programa. Foi mais trabalhoso, mas a apresenta- 03 # $2 - Valor a ser aceito com resposta padrão ção ficou muito legal e você explorou bastante as 04 # $3 - O outro valor aceito opções do comando tput. Vamos testar o resultado 05 # Supondo que $1=Aceita?, $2=s e $3=n, a linha com um álbum do Emerson, Lake & Palmer que 06 # abaixo colocaria em Msg o valor "Aceita? (S/n)" tenho cadastrado. 07 Msg="$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)" 08 TamMsg=${#Msg} Envenenando a escrita 09 Col=$(((TotCols - TamMsg) / 2)) # Centraliza msg na linha Ufa! Agora você já sabe tudo sobre leitura de dados, 10 tput cup $LinhaMesg $Col mas quanto à escrita ainda está apenas engatinhando. 11 read -n1 -p "$Msg " SN 12 [ ! $SN ] && SN=$2 # Se vazia coloca default em SN Já sei que você vai me perguntar: “Ora, não é com o 13 SN=$(echo $SN | tr A-Z a-z) # A saída de SN será em minúscula comando echo e com os redirecionamentos de saída 14 tput cup $LinhaMesg $Col; tput el # Apaga msg da tela que se escreve dados?”.84 junho 2005 edição 09 www.linuxmagazine.com.br
  2. 2. Papo de Botequim Linux User Listagem 2: listaartistaprintf formato [argumento...] $ cat listartista3.sh 01 #!/bin/bash Onde formato é uma cadeia 02 # Dado um artista, mostra as suas musicas 03 # versao 3de caracteres que contém três 04 LinhaMesg=$((`tput lines` - 3)) # Linha onde as msgs serão mostradastipos de objeto: caracteres 05 TotCols=$(tput cols) # Qtd de colunas na tela para enquadrar msgssimples, caracteres para es- 06 clearpecificação de formato (ou de 07 echo " +–––––––––––––––––-----------------------------------+controle) e seqüência de esca- | Lista Todas as Músicas de um Determinado Artista |pe no padrão da linguagem | ===== ===== == ======= == == =========== ======= |C. argumento é a cadeia de | |caracteres a ser impressa sob | Informe o Artista: | +––––––––––––––––----------------------------------–-+"o controle de formato. 08 while true Cada um dos caracteres uti- 09 dolizados é precedido pelo ca- 10 tput cup 5 51; tput ech 31 # ech=Erase chars (31 para não apagar barra vertical)racter % e, logo a seguir, vem 11 read Nomea especificação de formato de 12 if [ ! "$Nome" ] # $Nome esta vazio? 13 thenacordo com a tabela 1. 14 . pergunta.func "Deseja Sair?" s n As seqüências de escape 15 [ $SN = n ] && continuepadrão da linguagem C são 16 breaksempre precedidas pelo ca- 17 fi 18 fgrep -iq "^$Nome~" musicas || # fgrep não interpreta ^ como expressão regularractere contra-barra (). As 19 {reconhecidas pelo comando 20 . mandamsg.func "Não existe música desse artista"printf são as da tabela 2. 21 continue Não acaba por aí não! Tem 22 } 23 tput cup 7 29; echo | |muito mais coisa sobre essa 24 LinAtual=8instrução, mas como esse é 25 IFS="um assunto muito cheio de 26 :"detalhes e, portanto, chato 27 for ArtMus in $(cut -f2 -d^ musicas) # Exclui nome do album 28 dopara explicar e pior ainda para 29 if echo "$ArtMus" | grep -iq "^$Nome~"ler ou estudar, vamos passar 30 thendireto aos exemplos com co- 31 tput cup $LinAtual 29mentários. Veja só: 32 echo -n | " 33 echo $ArtMus | cut -f2 -d~ 34 tput cup $LinAtual 82$ printf "%c" "1 caracter" 35 echo |1$ 36 let LinAtual++ 37 if [ $LinAtual -eq $LinhaMesg ] Errado! Só listou 1 caractere 38 then 39 . mandamsg.func "Tecle Algo para Continuar..."e não saltou linha ao final 40 tput cup 7 0; tput ed # Apaga a tela a partir da linha 7 41 tput cup 7 29; echo | |$ printf "%cn" "1 caracter" 42 LinAtual=81 43 fi 44 fi 45 done Saltou linha mas ainda não 46 tput cup $LinAtual 29; echo | |listou a cadeia inteira 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$ printf "%c caracteren" 1 50 done1 caractere ➟ junho 2005 edição 09 85 www.linuxmagazine.com.br
  3. 3. Linux User Papo de Botequim Tabela 1: Formatos de caractere (%) significa o tamanho que a cadeia terá O bc devolveu duas casas decimais e após a execução do comando. Vamos ver o printf colocou o zero à direita. O co- Caractere A expressão será impressa como: c Caractere simples a seguir mais alguns exemplos. Os co- mando a seguir: d Número no sistema decimal mandos abaixo: e Notação científica exponencial $ printf "%on" 10 f Número com ponto decimal (float) $ printf "%dn" 32 12 g O menor entre os formatos %e e %f com 32 omissão dos zeros não significativos $ printf "%10dn" 32 Converteu o valor 10 para base octal. o Número no sistema octal 32 Para melhorar experimente: s Cadeia de caracteres x Número no sistema hexadecimal preenchem a string com espaços em $ printf "%03on" 27 % Imprime um %. Não há nenhum tipo de conversão branco à esquerda (oito espaços mais dois 033 caracteres, 10 dígitos), não com zeros. Já no comando abaixo: Assim a conversão fica com mais jeito Opa, essa é a forma correta! O %c rece- de octal, né?. O que este aqui faz? beu o valor 1, como queríamos: $ printf "%04dn" 32 0032 $ printf "%sn" Peteleca $ a=2 Peteleca $ printf "%c caracteresn" $a O 04 após % significa “formate a string $ printf "%15sn" Peteleca 2 caracteres em quatro dígitos, com zeros à esquerda Peteleca se necessário”. No comando: O %c recebeu o valor da variável $a. Imprime Peteleca com 15 caracteres. $ printf "%en" $(echo "scale=2 ; 100/6" | bc) A cadeia de caracteres é preenchida com $ printf "%10c caracteresn" $a 1.666000e+01 espaços em branco à esquerda. Já no co- 2 caracteres mando: $ printf "%10cn" $a caracteres O padrão do %e é seis casas decimais. 2 Já no comando: $ printf "%-15sNevesn" Peteleca c Peteleca Neves $ printf "%.2en" `echo "scale=2 ; 100/6" | bc` Repare que, nos dois últimos exemplos, 1.67e+01 O menos (-) colocou espaços em branco em virtude do uso do %c, só foi listado à direita de Peteleca até completar os 15 um caractere de cada cadeia de caracteres O .2 especificou duas casas decimais. caracteres pedidos. E o comando abaixo, passada como parâmetro. O valor 10 à Observe agora: o que faz? frente do c não significa 10 caracteres. Um número seguindo o sinal de percentagem $ printf "%fn" 32.3 $ printf "%.3sn" Peteleca 32.300000 Pet Tabela 2: Seqüências de escape O padrão do %f é seis casas decimais. O .3 manda truncar a cadeia de ca- Seqüência Efeito E no comando: racteres após as três primeiras letras. E a Soa o beep b Volta uma posição (backspace) o comando a seguir: f Salta para a próxima página $ printf "%.2fn" 32.3 lógica ( form feed) 32.30 $ printf "%10.3san" Peteleca n Salta para o início da linha se- Peta Pet guinte (line feed) O .2 especificou duas casas decimais. r Volta para o início da linha cor- Agora observe: Imprime a cadeia com 10 caracteres, rente (carriage return) truncada após os três primeiros, conca- t Avança para a próxima marca de tabulação $ printf "%.3fn" `echo "scale=2 ; 100/6" | bc` tenada com o caractere a (após o s). E 33.330 esse comando a seguir, o que faz?86 junho 2005 edição 09 www.linuxmagazine.com.br
  4. 4. Papo de Botequim Linux User $ printf “EXEMPLO %xn” 45232 trabalho, principalmente em instalações (1 minuto). A cada intervalo o Shell fará EXEMPLO b0b0 com estrutura de diretórios em múltiplos a verificação antes de exibir o próximo níveis. Veja o exemplo a seguir: prompt primário ($PS1). Se essa variável Ele transformou o número 45232 para estiver sem valor ou com um valor menorhexadecimal (b0b0), mas os zeros não $ echo $CDPATH ou igual a zero, a busca por novas men-combinam com o resto. Experimente: .:..:~:/usr/local sagens não será efetuada. $ pwd PATH » Caminhos que serão pesquisa- $ printf “EXEMPLO %Xn” 45232 /home/jneves/LM dos para tentar localizar um arquivo espe- EXEMPLO B0B0 $ cd bin cificado. Como cada script é um arquivo, $ pwd caso use o diretório corrente (.) na sua Assim disfarçou melhor! (repare no X /usr/local/bin variável $PATH, você não necessitará usarmaiúsculo). Pra terminar, que tal o co- o comando ./scrp para que o script scrpmando abaixo: Como /usr/local estava na minha seja executado. Basta digitar scrp. Este variável $CDPATH e não existia o diretório é o modo que prefiro. $ printf “%X %XL%Xn” 49354 192 10 bin em nenhum dos seus antecessores (., PIPESTATUS » É uma variável do tipo C0CA C0LA .. e ~), o comando cd foi executado tendo vetor (array) que contém uma lista de como destino /usr/local/bin. valores de códigos de retorno do último Este aí não é marketing e é bastante HISTSIZE » Limita o número de ins- pipeline executado, isto é, um array que completo, veja só como funciona: truções que cabem dentro do arquivo de abriga cada um dos $? de cada instrução O primeiro %X converteu 49354 em he- histórico de comandos (normalmente do último pipeline. Para entender melhor, xadecimal, resultando em C0CA (leia-se .bash_history, mas na verdade é o que veja o exemplo a seguir:“cê”, “zero”, “cê” e “a”). Em seguida veio está indicado na variável $HISTFILE). Seu um espaço em branco seguido por outro valor padrão é 500. $ who %XL. O %X converteu o 192 dando como HOSTNAME » O nome do host corrente jneves pts/0 Apr 11 16:26 (10.2.4.144) resultado C0 que com o L fez C0L. E final- (que também pode ser obtido com o co- jneves pts/1 Apr 12 12:04 (10.2.4.144) mente o último parâmetro %X transformou mando uname -n). $ who | grep ^botelho o número 10 na letra A. LANG » Usada para determinar o idioma $ echo ${PIPESTATUS[*]} Conforme vocês podem notar, a instru- falado no país (mais especificamente ca- 0 1 ção é bastante completa e complexa. Ain- tegoria do locale). Veja um exemplo: da bem que o echo resolve quase tudo... Neste exemplo mostramos que o usu- Acertei em cheio quando resolvi expli- $ date ário botelho não estava “logado”, em car o printf através de exemplos, pois Thu Apr 14 11:54:13 BRT 2005 seguida executamos um pipeline que não saberia como enumerar tantas regri- $ LANG=pt_BR date procurava por ele. Usa-se a notação [*] nhas sem tornar a leitura enfadonha. Qui Abr 14 11:55:14 BRT 2005 em um array para listar todos os seus elementos; dessa forma, vimos que a pri- Principais variáveis do Shell LINENO » O número da linha do script meira instrução (who) foi bem-sucedidaO Bash possui diversas variáveis que ou função que está sendo executada. (código de retorno 0) e a seguinte (grep)servem para dar informações sobre Seu uso principal é mostrar mensagens não (código de retorno 1).o ambiente ou alterá-lo. São muitas e de erro juntamente com as variáveis $0 PROMPT_COMMAND » Se esta variável re-não pretendo mostrar todas elas, mas (nome do programa) e $FUNCNAME (nome ceber o nome de um comando, toda vezuma pequena parte pode lhe ajudar na da função em execução). que você teclar um [ENTER] sozinho noelaboração de scripts. Veja a seguir as LOGNAME » Esta variável armazena o prompt principal ($PS1), esse comandoprincipais delas: nome de login do usuário . será executado. É muito útil quando você CDPATH » Contém os caminhos que MAILCHECK » Especifica, em segundos, a precisa repetindo constantemente umaserão pesquisados para tentar localizar freqüência com que o Shell verifica a pre- determinada instrução.um diretório especificado. Apesar dessa sença de correspondência nos arquivos PS1 » É o prompt principal. No “Papovariável ser pouco conhecida, seu uso indicados pela variáveis $MAILPATH ou de Botequim” usamos os padrões $ paradeve ser incentivado por poupar muito $MAIL. O tempo padrão é de 60 segundos usuário comum e # para root, mas é mui- junho 2005 edição 09 87 www.linuxmagazine.com.br
  5. 5. Linux User Papo de Botequim to freqüente que ele esteja personalizado. Expansão de parâmetros $ cadeia="Papo de Botequim" Uma curiosidade é que existe até concurso Bem, muito do que vimos até agora são $ echo ${cadeia#* } de quem programa o $PS1 mais criativo. comandos externos ao Shell. Eles quebram de Botequim PS2 » Também chamado “prompt de o maior galho, facilitam a visualização, $ echo "Conversa "${cadeia#* } continuação”, é aquele sinal de maior manutenção e depuração do código, mas Conversa de Botequim (>) que aparece após um [ENTER] sem não são tão eficientes quanto os intrínse- o comando ter sido encerrado. cos (built-ins). Quando o nosso problema No exemplo anterior foi suprimido à PWD » Possui o caminho completo for performance, devemos dar preferência esquerda tudo o que “casa” com a menor ($PATH) do diretório corrente. Tem o ao uso dos intrínsecos. A partir de agora ocorrência da expressão *’ ‘, ou seja, mesmo efeito do comando pwd. vou te mostrar algumas técnicas para o todos os caracteres até o primeiro espaço RANDOM » Cada vez que esta variável é seu programa pisar no acelerador. em branco. Esses exemplos também po- acessada, devolve um inteiro aleatório en- Na tabela 3 e nos exemplos a seguir, deriam ser escritos sem proteger o espaço tre 0 e 32767. Para gerar um inteiro entre veremos uma série de construções cha- da interpretação do Shell (mas prefiro 0 e 100, por exemplo, digitamos: madas expansão (ou substituição) de protegê-lo para facilitar a legibilidade parâmetros (Parameter Expansion), que do código). Veja só: $ echo $((RANDOM%101)) substituem instruções como o cut, o expr, 73 o tr, o sed e outras de forma mais ágil. $ echo ${cadeia#* } Vamos ver alguns exemplos: se em uma de Botequim Ou seja, pegamos o resto da divisão do pergunta o S é oferecido como valor de- $ echo "Conversa "${cadeia#* } número randômico gerado por 101 porque fault (padrão) e a saída vai para a variável Conversa de Botequim o resto da divisão de qualquer número SN, após ler o valor podemos fazer: por 101 varia entre 0 e 100. Repare que na construção de expr é REPLY » Use esta variável para recuperar SN=$(SN:-S} permitido o uso de metacaracteres. o último campo lido, caso ele não tenha Utilizando o mesmo valor da variável nenhuma variável associada. Exemplo: Para saber o tamanho de uma cadeia: cadeia, observe como faríamos para ter somente Botequim : $ read -p "Digite S ou N: " $ cadeia=0123 Digite S ou N: N $ echo ${#cadeia} $ echo ${cadeia##* } $ echo $REPLY 4 Botequim N $ echo "Vamos Chopear no "${cadeia##* } Para extrair dados de cadeia, da posi- Vamos Chopear no Botequim SECONDS » Esta variável informa, em se- ção um até o final fazemos: gundos, há quanto tempo o Shell corrente Desta vez suprimimos à esquerda de está “de pé”. Use-a para demonstrar a $ cadeia=abcdef cadeia a maior ocorrência da expressão estabilidade do Linux e esnobar usuários $ echo ${cadeia:1} expr. Assim como no caso anterior, o uso daquela coisa com janelinhas coloridas bcdef de metacaracteres é permitido. que chamam de sistema operacional, mas Outro exemplo mais útil: para que não que necessita de “reboots” freqüentes. Repare que a origem é zero e não um. apareça o caminho (path) completo do seu TMOUT » Se esta variável contiver um Vamos extrair 3 caracteres a partir da 2ª programa ($0) em uma mensagem de erro, valor maior do que zero, esse valor posição da mesma variável cadeia: inicie o seu texto da seguinte forma: será considerado o timeout padrão do comando read. No prompt, esse valor $ echo ${cadeia:2:3} echo Uso: ${0##*/} texto da mensagem de erro é interpretado como o tempo de espera cde por uma ação antes de expirar a sessão. Neste exemplo seria suprimido à es- Supondo que a variável contenha o valor Repare que novamente a origem da con- querda tudo até a última barra (/) do 30, o Shell encerrará a sessão do usuário tagem é zero e não um. Para suprimir caminho, restando somente o nome do (ou seja, fará logout) após 30 segundos tudo à esquerda da primeira ocorrência programa. O caractere % é simétrico ao sem nenhuma ação no prompt. de uma cadeia, faça: #, veja o exemplo:88 junho 2005 edição 09 www.linuxmagazine.com.br
  6. 6. Papo de Botequim Linux User Tabela 3: Tipos de expansão de parâmetros Há várias formas de trocar uma subca- deia no início ou no fim de uma variável. Expansão de parâmetros Resultado esperado Para trocar no início fazemos:${var:-padrao} Se var é vazia, o resultado da expressão é padrão${#cadeia} Tamanho de $cadeia${cadeia:posicao} Extrai uma subcadeia de $cadeia a partir de posição. Origem zero $ echo $Passaro${cadeia:posicao:tamanho} Extrai uma subcadeia de $cadeia a partir de posição com tamanho quero quero igual a tamanho. Origem zero $ echo “Como diz o sulista - “${PassaroU${cadeia#expr} Corta a menor ocorrência de $cadeia à esquerda da expressão expr /#quero/não}${cadeia##expr} Corta a maior ocorrência de $cadeia à esquerda da expressão expr Como diz o sulista - não quero${cadeia%expr} Corta a menor ocorrência de $cadeia à direita da expressão expr${cadeia%%expr} Corta a maior ocorrência de $cadeia à direita da expressão expr Para trocar no final fazemos:${cadeia/subcad1/subcad2} Troca a primeira ocorrência de subcad1 por subcad2${cadeia//subcad1/subcad2} Troca todas as ocorrências de subcad1 por subcad2${cadeia/#subcad1/subcad2} Se subcad1 combina com o início de cadeia, então é trocado por subcad2 $ echo “Como diz o nordestino - U${cadeia/%subcad1/subcad2} Se subcad1 combina com o fim de cadeia, então é trocado por subcad2 “${Passaro/%quero/não} Como diz o nordestino - quero não$ echo $cadeia $ echo ${cadeia/*po/Conversa} – Agora já chega, o papo hoje foi chatoPapo de Botequim Conversa de Botequim porque teve muita decoreba, mas o que$ echo ${cadeia% *} $ echo ${cadeia/????/Conversa} mais importa é você ter entendido oPapo de Conversa de Botequim que te falei. Quando precisar, consulte$ echo ${cadeia%% *} estes guardanapos onde rabisquei asPapo Trocando todas as ocorrências de uma dicas e depois guarde-os para consultas subcadeia por outra. O comando: futuras. Mas voltando à vaca fria: tá Para trocar primeira ocorrência de uma na hora de tomar outro e ver o jogo dosubcadeia em uma cadeia por outra: $ echo ${cadeia//o/a} Mengão. Pra próxima vez vou te dar Papa de Batequim moleza e só vou cobrar o seguinte: pe-$ echo $cadeia gue a rotina pergunta.func (da qualPapo de Botequim Ordena a troca de todos as letras o por falamos no início do nosso bate-papo$ echo ${cadeia/de/no} a. Outro exemplo mais útil é para contar de hoje, veja a listagem 1) e otimize-aPapo no Botequim a quantidade de arquivos existentes no para que a variável $SN receba o valor$ echo ${cadeia/de /} diretório corrente. Observe o exemplo: padrão por expansão de parâmetros,Papo Botequim como vimos. $ ls | wc -l E não se esqueça: em caso de dúvidas Preste atenção quando for usar metaca- 30 ou falta de companhia para um (ou mais)racteres! Eles são gulosos e sempre com- chope é só mandar um e-mail para julio.binarão com a maior possibilidade; No O wc põe um monte de espaços em neves@gmail.com. E diga para os amigosexemplo a seguir eu queria trocar Papo de branco antes do resultado. Para tirá-los: que quem estiver a fim de fazer um cursoBotequim por Conversa de Botequim: porreta de programação em Shell deve # QtdArqs recebe a saída do comando mandar um e-mail para julio.neves@tecnohall.$ echo $cadeia $ QtdArqs=$(ls | wc -l) com.br para informar-se. Valeu! ■Papo de Botequim $ echo ${QtdArqs/ * /}$ echo ${cadeia/*o/Conversa} 30 Julio Cezar Neves é Analista de Suporte de Sobre o autorConversatequim Sistemas desde 1969 e trabalha com Unix Nesse exemplo, eu sabia que a saída era desde 1980, quando participou do desen- A idéia era pegar tudo até o primeiro composta de brancos e números, por isso volvimento do SOX, um sistema operacio-o, mas acabou sendo trocado tudo até o montei essa expressão para trocar todos os nal similar ao Unix produzido pela Cobraúltimo o. Isto poderia ser resolvido de espaços por nada. Note que antes e após o Computadores. Pode ser contatado nodiversas maneiras. Eis algumas: asterisco (*) há espaços em branco. e-mail julio.neves@gmail.com junho 2005 edição 09 89 www.linuxmagazine.com.br

×