\
for? Eu te deixei um exercício para treinar, se não me engano era para contar a quantidade de palavras de um arquivo... Você fez?
- Claro! Tô empolgadão com essa linguagem, eu fiz da forma que você pediu, isto é sem usar o comando wc porque senão era mais mole ainda. Olha só como eu fi...
- Êpa! Perai! Você realmente está fissurado na linguagem, mas eu tô sequinho pra tomar um chope. Aê Chico, traz dois por favor. Um sem colarinho!
- Como eu ia dizendo olha a forma que eu fiz. É muito fácil...
for se incumbe de pegar cada uma das palavras (lembre-se que o $IFS padrão (default) é branco, <TAB> e <ENTER>, que é exatamente o que desejamos para separar as palavras), incrementando a variável $Cont.
Vamos relembrar como é o arquivo ArqDoDOS.txt.
for e Matemática for a seguir:
for ((; i<=9;))
do
let i++
echo -n "$i "
done
Uma vez que chegamos neste ponto, creio ser bastante interessante citar que o Shell trabalha com o conceito de "Expansão Aritmética" (Arithmetic Expansion), da qual vou falar rapidamente porque na seção Tira Gosto isso está muito bem mastigado.
A expansão aritmética é acionada por uma construção da forma:
$((expressão))
ou
let expressão
No último for citado usei a expansão das duas formas, mas não poderíamos seguir adiante sem saber que a expressão pode ser de uma das listadas a seguir:
| Expansão Aritmética | |
|---|---|
|| |
OU lógico |
| Expressão | Resultado |
id++ id-- |
pós-incremento e pós-decremento de variáveis |
++id -–id |
pré-incremento e pré-decremento de variáveis |
** |
exponenciação |
* / % |
multiplicação, divisão, resto da divisão |
+ - |
adição, subtração |
<= >= < > |
comparação |
== != |
igualdade, desigualdade |
&& |
E lógico |
for? Ledo engano amigo, vamos a partir de agora ver mais dois.
while while junto com o comando test, exatamente como você aprendeu a fazer no if, lembra?
Então a sintaxe do comando fica assim:
while comando
do
cmd1
cmd2
...
cmdn
done
e desta forma o bloco de comandos formado pelas instruções cmd1, cmd2,... e cmdn é executado enquanto a execução da instrução comando for bem sucedida.
Suponha a seguinte cena: tem uma tremenda gata me esperando e eu preso no trabalho sem poder sair porque o meu chefe, que é um pé no saco (aliás chefe-chato é uma redundância, né?:), ainda estava na sua sala, que fica bem na minha passagem para a rua.
Ele começou a ficar com as antenas (provavelmente instaladas na cabeça dele pela esposa) ligadas depois da quinta vez que passei pela sua porta e olhei para ver se já havia ido embora. Então voltei para a minha mesa e fiz, no servidor, um script assim:
while testa o pipeline composto pelo who e pelo grep e que será verdadeiro enquanto o grep localizar a palavra xefe na saída do who. Desta forma, o script dormirá por 30 segundos enquanto o chefe estiver logado (Argh!). Assim que ele se desconectar do servidor, o fluxo do script sairá do loop e dará a tão ansiada mensagem de liberdade.
Quando o executei adivinha o que aconteceu?
grep, o que não seria legal já que poluiria a tela do meu micro e a mensagem esperada poderia passar desapercebida. Para evitar isso já sabemos que a saída do pipeline tem que ser redirecionada para /dev/null.
$! guarda o PID (Process IDentification) do último processo em background, mas repare após a linha do done, que a variável reteve o valor mesmo após o término deste processo.
Bem sabendo isso já fica mais fácil de monitorar qualquer processo em background. Veja só como:
$! será o do programa passado como parâmetro já que ele foi colocado em background após o monbg.sh propriamente dito. Repare também a opção -q (quiet) do grep, ela serve para tranformá-lo num comando mineiro, isto é, para o grep "trabalhar em silêncio". O mesmo resultado poderia ser obtido se a linha fosse while ps | grep $! > /dev/null, como nos exemplos que vimos até agora.
Não esqueça: o Bash disponibiliza a variável $! que possui o PID (Process IDentification) do último processo executado em background.
musinc, que é o nosso programa para incluir registros no arquivo musicas, mas antes preciso te ensinar a pegar um dado da tela, e já vou avisando: só vou dar uma pequena dica do comando read (que é quem pega o dado da tela) que seja o suficiente para resolver este nosso problema. Em uma outra rodada de chope vou te ensinar tudo sobre o assunto, inclusive como formatar tela, mas hoje estamos falando sobre loops.
A sintaxe do comando read que nos interessa por hoje é a seguinte:
prompt de leitura é o texto que você quer que apareça escrito na tela, e quando o operador teclar o dado, ele irá para a variável var. Por exemplo:
<ENTER>. Para facilitar a vida do operador, vamos oferecer como default o mesmo nome do artista da música anterior (já que é normal que o álbum seja todo do mesmo artista) até que ele deseje alterá-lo. Vamos ver como ficou:
grep procura no início (^) de cada registro de musicas, o título informado seguido do separador (^) (que está precedido de uma contrabarra (\) para protegê-lo da interpretação do Shell).
Para ler os nomes dos artistas e as músicas do álbum, foi montado um loop de while simples, cujo único destaque é o fato de estar armazenando o artista da música anterior na variável $oArt que só terá o seu conteúdo alterado, quando algum dados for informado para a variável $Art, isto é, quando não teclou-se um simples <ENTER> para manter o artista anterior.
O que foi visto até agora sobre o while foi muito pouco. Este comando é muito utilizado, principalmente para leitura de arquivos, porém nos falta bagagem para prosseguir. Depois que aprendermos a ler, veremos esta instrução mais a fundo.
Leitura de arquivo significa ler um-a-um todos os registros, o que é sempre uma operação lenta. Fique atento para não usar o while quando seu uso for desnecessário. O Shell tem ferramentas como o sed e a família grep que vasculham arquivos de forma otimizada sem ser necessário o uso de comandos de loop para fazê-lo registro a registro (ou até palavra a palavra).
until until funciona exatamente igual ao while, porém ao contrário. Disse tudo mas não disse nada, né? É o seguinte: ambos testam comandos; ambos possuem a mesma sintaxe e ambos atuam em loop, porém enquanto o while executa o bloco de intruções do loop enquanto um comando for bem sucedido, o until executa o bloco do loop até que o comando seja bem sucedido. Parece pouca coisa mas a diferença é fundamental.
A sintaxe do comando é praticamente a mesma do while. Veja:
until comando
do
cmd1
cmd2
...
cmdn
done
E desta forma o bloco de comandos formado pelas instruções cmd1, cmd2,... e cmdn é executado até que a execução da instrução comando seja bem sucedida.
Como eu te disse, o while e until funcionam de forma antagônica e isso é muito fácil de demonstrar: em uma guerra sempre que se inventa uma arma, o inimigo busca uma solução para neutralizá-la. Baseado neste principio belicoso que o meu chefe, desenvolveu, no mesmo servidor que eu executava o logaute.sh um script para controlar o meu horário de chegada.
Um dia deu um problema da rede, ele me pediu para dar uma olhada no micro dele e me deixou sozinho em sua sala. Imediatamente comecei a bisbilhotar seus arquivos - porque guerra é guerra - e veja só o que descobri:
relapso.log! O que será que ele quis dizer com isso?
Neste script, o pipeline who | grep julio, será bem sucedido somente quando julio for encontrado no comando who, isto é, quando eu me "logar" no servidor. Até que isso aconteça, o comando sleep, que forma o bloco de instruções do until, porá o programa em espera por 30 segundos. Quando este loop encerrar-se, será dada uma mensagem para o relapso.log (ARGHH!). Supondo que no dia 20/01 eu me loguei às 11:23 horas, a mensagem seria a seguinte:
Em 20/01 às 11:23h
Quando vamos cadastrar músicas, o ideal seria que pudéssemos cadastrar diversos CDs, e na última versão que fizemos do musinc, isso não ocorre, a cada CD que cadastramos o programa termina. Vejamos como melhorá-lo:
$Para deixar de ser vazia. Caso o título do álbum não seja informado, a variável $Para receberá valor (no caso coloquei 1 mas poderia ter colocado qualquer coisa. O importante é que não seja vazia) para sair deste loop, terminando desta forma o programa. No resto, o script é idêntico à sua versão anterior.
do e um done, sai pela porta da frente. Em algumas oportunidades, temos que colocar um comando que aborte de forma controlada este loop. De maneira inversa, algumas vezes desejamos que o fluxo de execução do programa volte antes de chegar ao done. Para isto, temos respectivamente, os comandos break (que já vimos rapidamente nos exemplos do comado while) e continue, que funcionam da seguinte forma:
O que eu não havia dito anteriormente é que nas suas sintaxes genéricas eles aparecem da seguinte forma:
break [qtd loop]
e
continue [qtd loop]
Onde qtd loop representa a quantidade dos loops mais internos sobre os quais os comandos irão atuar. Seu valor default é 1.
erreeme e no /etc/profile coloquei a seguinte linha:
alias rm=erreeme
O programa era assim:
continue, para que a sequência volte para o loop do for de forma a receber outros arquivos.
Quando você está no Windows (com perdão da má palavra) e tenta remover aquele monte de lixo com nomes esquisitos como HD04TG.TMP, se der erro em um deles, os outros não são removidos, não é? Então, o continue foi usado para evitar que um impropério desses ocorra, isto é, mesmo que dê erro na remoção de um arquivo, o programa continuará removendo os outros que foram passados.
- Eu acho que a esta altura você deve estar curioso para ver o programa que restaura o arquivo removido, não é? Pois então aí vai vai um desafio: faça-o em casa e me traga para discutirmos no nosso próximo encontro aqui no boteco.
- Poxa, mas nesse eu acho que vou dançar, pois não sei nem como começar...
- Cara, este programa é como tudo que se faz em Shell, extremamente fácil, é para ser feito em, no máximo 10 linhas. Não se esqueça que o arquivo está salvo em /tmp/$LOGNAME e que a sua última linha é o diretório em que ele residia antes de ser "removido". Também não se esqueça de criticar se foi passado o nome do arquivo a ser removido.
- É eu vou tentar, mas sei não...
- Tenha fé irmão, eu tô te falando que é mole! Qualquer dúvida é só me passar um e-mail para julio.neves@gmail.com. Agora chega de papo que eu já estou de goela seca de tanto falar. Me acompanha no próximo chope ou já vai sair correndo para fazer o script que passei?
- Deixa eu pensar um pouco...
- Chico, traz mais um chope enquanto ele pensa!
Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em Shell que mande um e-mail para a nossa gerencia de treinamento para informar-se.
Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para mim.
Valeu!
(CC) 2009 Pelos Frequentadores do Bar do Júlio Neves.