Академический Документы
Профессиональный Документы
Культура Документы
Verso 1.0.0
Sumrio
I Sobre essa Apostila 2 4 9 18
19 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 20 20 20 20 20 21 21 22 23 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 24 24 25 26 28 28 28 29 29 29 29 30 30
1 O que Shell Script 2 Plano de ensino 2.1 Objetivo . . . 2.2 Pblico Alvo . 2.3 Pr-requisitos 2.4 Descrio . . 2.5 Metodologia . 2.6 Programa . . 2.7 Avaliao . . 2.8 Bibliograa . 3 Introduo 4 Expresses Regulares 4.1 Introduo . . . . . . . . . . . . 4.2 Comando grep . . . . . . . . . 4.3 Os Metacaracteres . . . . . . . 4.4 Metacaracteres quanticadores 4.5 Metacaracteres tipo ncora . . 4.5.1 Circunexo . . . . . . 4.5.2 Cifro - o m . . . . . 4.5.3 Borda - a limtrofe . . . 4.6 Outros metacaracteres . . . . 4.7 Explicando-os melhor . . . . . 4.7.1 Escape . . . . . . . . . 4.7.2 Ou . . . . . . . . . . . . 4.7.3 Grupo . . . . . . . . . . . . . . . . . .
CDTC
Brasil/DF
4.7.4 Retrovisor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 5 Parte I 5.1 Dilogo . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 O ambiente Linux . . . . . . . . . . . . . . . . . . . . . . 5.3 O ambiente Shell . . . . . . . . . . . . . . . . . . . . . . 5.4 Uma rpida passagem nos principais sabores de Shell . 5.5 Explicando o funcionamento do Shell . . . . . . . . . . 5.6 Caracteres para remoo do signicado . . . . . . . . . 5.7 Caracteres de redirecionamento . . . . . . . . . . . . . 5.7.1 Caracteres de redirecionamento . . . . . . . . . 5.7.2 Redirecionamento da Sada Padro . . . . . . . 5.7.3 Redirecionamento da Sada de erro Padro . . . 5.7.4 Redirecionamento da Entrada Padro . . . . . . 5.8 Redirecionamento de Comandos . . . . . . . . . . . . . 5.9 Caracteres de Ambiente . . . . . . . . . . . . . . . . . . 6 Parte II 6.1 Dilogo . . . . . . . . . . . . . . . . . 6.2 Eu co com o grep, voc com a gripe 6.3 A famlia grep . . . . . . . . . . . . . . 6.4 Exemplos da famlia grep . . . . . . . 6.5 Vamos montar uma cdteca . . . . . . 6.6 Passando parmetros . . . . . . . . . 6.7 Macetes paramtricos . . . . . . . . . 7 Parte III 7.1 Trabalhando com cadeias . . . . . . . 7.2 O comando cut . . . . . . . . . . . . . 7.2.1 O comando cut a opo -c . . 7.2.2 O comando cut a opo -f . . . 7.3 O comando tr . . . . . . . . . . . . . . 7.3.1 Trocando caracteres com tr . . 7.3.2 Removendo caracteres com tr 7.3.3 Xpremendo com tr . . . . . . . 7.3.4 O Comando if . . . . . . . . . . 8 Parte IV 8.1 Dilogo . . . . . . . . . . . . . . . . 8.2 O comando Test . . . . . . . . . . . 8.3 Continuao do comando test . . . 8.4 Encolheram o comando condicional 8.5 E tome de test . . . . . . . . . . . . 8.6 Acaso casa com case . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 33 33 34 34 35 37 38 38 38 39 40 41 42 46 46 46 47 48 49 49 51 57 57 57 57 58 60 60 61 62 63 67 67 68 70 73 75 76
CDTC
Brasil/DF
9 Parte V 9.1 Comandos de Loop (ou lao) . . . . . . 9.2 O Comando for . . . . . . . . . . . . . . 9.2.1 Primeira sintaxe do comando for 9.2.2 Segunda sintaxe do comando for 9.2.3 Terceira sintaxe do comando for 10 Parte VI 10.1 Um pouco mais de for e matemtica 10.2 O Comando while . . . . . . . . . . 10.3 O Comando Until . . . . . . . . . . . 10.4 Atalhos no loop . . . . . . . . . . . . . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
79 79 79 79 84 86 88 88 89 93 95
11 Parte VII 99 11.1 O comando tput . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 11.2 E agora podemos ler os dados na tela . . . . . . . . . . . . . . . . . . . . . . . . . . 101 11.3 Vamos ler arquivos? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 12 Parte VIII 110 12.1 Funes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 12.2 O comando source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 13 Parte IX 13.1 Envenenando a escrita . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13.2 Principais Variveis do Shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13.3 Expanso de parmetros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 Parte X 14.1 O comando eval . . 14.2 Sinais de Processos 14.3 Sinais assassinos . 14.4 O trap no atrapalha 14.5 O comando getopts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 . 120 . 122 . 125 . . . . . . . . . 130 130 133 134 134 138 142 142 143 144 146
15 Parte XI 15.1 Named Pipes . . . . . . . . . 15.2 Sincronizao de processos . 15.3 Bloqueio de arquivos . . . . . 15.4 Substituio de processos . .
Parte I
CDTC
Brasil/DF
Contedo
O contedo dessa apostila fruto da compilao de diversos materiais livres publicados na internet, disponveis em diversos sites ou originalmente produzido no CDTC (http://www.cdtc.org.br.) O formato original deste material bem como sua atualizao est disponvel dentro da licena GNU Free Documentation License, cujo teor integral encontra-se aqui reproduzido na seo de mesmo nome, tendo inclusive uma verso traduzida (no ocial). A reviso e alterao vem sendo realizada pelo CDTC (suporte@cdtc.org.br) desde outubro de 2006. Crticas e sugestes construtivas sero bem-vindas a qualquer hora.
Autores
A autoria deste de responsabilidade de Waldemar Silva Jnior (waldemar@cdtc.org.br). O texto original faz parte do projeto Centro de Difuso de Tecnologia e Conhecimento que vm sendo realizado pelo ITI (Instituto Nacional de Tecnologia da Informao) em conjunto com outros parceiros institucionais, e com as universidades federais brasileiras que tem produzido e utilizado Software Livre apoiando inclusive a comunidade Free Software junto a outras entidades no pas. Informaes adicionais podem ser obtidas atravs do email ouvidoria@cdtc.org.br, ou da home page da entidade, atravs da URL http://www.cdtc.org.br.
Garantias
O material contido nesta apostila isento de garantias e o seu uso de inteira responsabilidade do usurio/leitor. Os autores, bem como o ITI e seus parceiros, no se responsabilizam direta ou indiretamente por qualquer prejuzo oriundo da utilizao do material aqui contido.
Licena
Copyright 2006, Instituto Nacional de Tecnologia da Informao (cdtc@iti.gov.br) . Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; with the Invariant Chapter being SOBRE ESSA APOSTILA. A copy of the license is included in the section entitled GNU Free Documentation License.
Parte II
Informaes Bsicas
CDTC
Brasil/DF
Sobre o CDTC
Objetivo Geral O Projeto CDTC visa a promoo e o desenvolvimento de aes que incentivem a disseminao de solues que utilizem padres abertos e no proprietrios de tecnologia, em proveito do desenvolvimento social, cultural, poltico, tecnolgico e econmico da sociedade brasileira. Objetivo Especco Auxiliar o Governo Federal na implantao do plano nacional de software no-proprietrio e de cdigo fonte aberto, identicando e mobilizando grupos de formadores de opinio dentre os servidores pblicos e agentes polticos da Unio Federal, estimulando e incentivando o mercado nacional a adotar novos modelos de negcio da tecnologia da informao e de novos negcios de comunicao com base em software no-proprietrio e de cdigo fonte aberto, oferecendo treinamento especco para tcnicos, prossionais de suporte e funcionrios pblicos usurios, criando grupos de funcionrios pblicos que iro treinar outros funcionrios pblicos e atuar como incentivadores e defensores dos produtos de software no proprietrios e cdigo fonte aberto, oferecendo contedo tcnico on-line para servios de suporte, ferramentas para desenvolvimento de produtos de software no proprietrios e do seu cdigo fonte livre, articulando redes de terceiros (dentro e fora do governo) fornecedoras de educao, pesquisa, desenvolvimento e teste de produtos de software livre.
Guia do aluno
Neste guia, voc ter reunidas uma srie de informaes importantes para que voc comece seu curso. So elas: Licenas para cpia de material disponvel; Os 10 mandamentos do aluno de Educao a Distncia; Como participar dos foruns e da wikipdia; Primeiros passos. muito importante que voc entre em contato com TODAS estas informaes, seguindo o roteiro acima.
Licena
Copyright 2006, Instituto Nacional de Tecnologia da Informao (cdtc@iti.gov.br). 7
CDTC
Brasil/DF
dada permisso para copiar, distribuir e/ou modicar este documento sob os termos da Licena de Documentao Livre GNU, Verso 1.1 ou qualquer verso posterior pblicada pela Free Software Foundation; com o Capitulo Invariante SOBRE ESSA APOSTILA. Uma cpia da licena est inclusa na seo entitulada "Licena de Documentao Livre GNU".
1. Acesso Internet: ter endereo eletrnico, um provedor e um equipamento adequado pr-requisito para a participao nos cursos a distncia; 2. Habilidade e disposio para operar programas: ter conhecimentos bsicos de Informtica necessrio para poder executar as tarefas; 3. Vontade para aprender colaborativamente: interagir, ser participativo no ensino a distncia conta muitos pontos, pois ir colaborar para o processo ensino-aprendizagem pessoal, dos colegas e dos professores; 4. Comportamentos compatveis com a etiqueta: mostrar-se interessado em conhecer seus colegas de turma respeitando-os e se fazendo ser respeitado pelos mesmos; 5. Organizao pessoal: planejar e organizar tudo fundamental para facilitar a sua reviso e a sua recuperao de materiais; 6. Vontade para realizar as atividades no tempo correto: anotar todas as suas obrigaes e realiz-las em tempo real; 7. Curiosidade e abertura para inovaes: aceitar novas idias e inovar sempre; 8. Flexibilidade e adaptao: requisitos necessrio mudana tecnolgica, aprendizagens e descobertas; 9. Objetividade em sua comunicao: comunicar-se de forma clara, breve e transparente ponto - chave na comunicao pela Internet; 10. Responsabilidade: ser responsvel por seu prprio aprendizado. O ambiente virtual no controla a sua dedicao, mas reete os resultados do seu esforo e da sua colaborao.
CDTC
Brasil/DF
todos participantes. Assim, se o monitor ou algum outro participante tiver uma informao que interesse ao grupo, favor post-la aqui. Porm, se o que voc deseja resolver alguma dvida ou discutir algum tpico especco do curso. recomendado que voc faa uso do Frum de dvidas gerais que lhe d recursos mais efetivos para esta prtica. . O frum de dvidas gerais tem por objetivo disponibilizar um meio fcil, rpido e interativo para solucionar suas dvidas e trocar experincias. As mensagens postadas nele so enviadas a todos participantes do curso. Assim, ca muito mais fcil obter respostas, j que todos podem ajudar. Se voc receber uma mensagem com algum tpico que saiba responder, no se preocupe com a formalizao ou a gramtica. Responda! E no se esquea de que antes de abrir um novo tpico recomendvel ver se a sua pergunta j foi feita por outro participante. A segunda forma se d pelas Wikis: . Uma wiki uma pgina web que pode ser editada colaborativamente, ou seja, qualquer participante pode inserir, editar, apagar textos. As verses antigas vo sendo arquivadas e podem ser recuperadas a qualquer momento que um dos participantes o desejar. Assim, ela oferece um timo suporte a processos de aprendizagem colaborativa. A maior wiki na web o site "Wikipdia", uma experincia grandiosa de construo de uma enciclopdia de forma colaborativa, por pessoas de todas as partes do mundo. Acesse-a em portugus pelos links: Pgina principal da Wiki - http://pt.wikipedia.org/wiki/ Agradecemos antecipadamente a sua colaborao com a aprendizagem do grupo!
Primeiros Passos
Para uma melhor aprendizagem recomendvel que voc siga os seguintes passos: Ler o Plano de Ensino e entender a que seu curso se dispe a ensinar; Ler a Ambientao do Moodle para aprender a navegar neste ambiente e se utilizar das ferramentas bsicas do mesmo; Entrar nas lies seguindo a seqncia descrita no Plano de Ensino; Qualquer dvida, reporte ao Frum de Dvidas Gerais.
Perl do Tutor
Segue-se uma descrio do tutor ideal, baseada no feedback de alunos e de tutores. O tutor ideal um modelo de excelncia: consistente, justo e prossional nos respectivos valores e atitudes, incentiva mas honesto, imparcial, amvel, positivo, respeitador, aceita as idias dos estudantes, paciente, pessoal, tolerante, apreciativo, compreensivo e pronto a ajudar. 9
CDTC
Brasil/DF
A classicao por um tutor desta natureza proporciona o melhor feedback possvel, crucial, e, para a maior parte dos alunos, constitui o ponto central do processo de aprendizagem. Este tutor ou instrutor: fornece explicaes claras acerca do que ele espera e do estilo de classicao que ir utilizar; gosta que lhe faam perguntas adicionais; identica as nossas falhas, mas corrige-as amavelmente, diz um estudante, e explica porque motivo a classicao foi ou no foi atribuda; tece comentrios completos e construtivos, mas de forma agradvel (em contraste com um reparo de um estudante: os comentrios deixam-nos com uma sensao de crtica, de ameaa e de nervossismo) d uma ajuda complementar para encorajar um estudante em diculdade; esclarece pontos que no foram entendidos, ou corretamente aprendidos anteriormente; ajuda o estudante a alcanar os seus objetivos; exvel quando necessrio; mostra um interesse genuno em motivar os alunos (mesmo os principiantes e, por isso, talvez numa fase menos interessante para o tutor); escreve todas as correes de forma legvel e com um nvel de pormenorizao adequado; acima de tudo, devolve os trabalhos rapidamente;
10
Parte III
11
CDTC
Brasil/DF
(Traduzido pelo Joo S. O. Bueno atravs do CIPSGA em 2001) Esta uma traduo no ocial da Licena de Documentao Livre GNU em Portugus Brasileiro. Ela no publicada pela Free Software Foundation, e no se aplica legalmente a distribuio de textos que usem a GFDL - apenas o texto original em Ingls da GNU FDL faz isso. Entretanto, ns esperamos que esta traduo ajude falantes de portugus a entenderem melhor a GFDL. This is an unofcial translation of the GNU General Documentation License into Brazilian Portuguese. It was not published by the Free Software Foundation, and does not legally state the distribution terms for software that uses the GFDLonly the original English text of the GFDL does that. However, we hope that this translation will help Portuguese speakers understand the GFDL better. Licena de Documentao Livre GNU Verso 1.1, Maro de 2000 Copyright (C) 2000 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA permitido a qualquer um copiar e distribuir cpias exatas deste documento de licena, mas no permitido alter-lo.
INTRODUO
O propsito desta Licena deixar um manual, livro-texto ou outro documento escrito "livre"no sentido de liberdade: assegurar a qualquer um a efetiva liberdade de copi-lo ou redistribui-lo, com ou sem modicaes, comercialmente ou no. Secundariamente, esta Licena mantm para o autor e editor uma forma de ter crdito por seu trabalho, sem ser considerado responsvel pelas modicaes feitas por terceiros. Esta Licena um tipo de "copyleft"("direitos revertidos"), o que signica que derivaes do documento precisam ser livres no mesmo sentido. Ela complementa a GNU Licena Pblica Geral (GNU GPL), que um copyleft para software livre. Ns zemos esta Licena para que seja usada em manuais de software livre, por que software livre precisa de documentao livre: um programa livre deve ser acompanhado de manuais que provenham as mesmas liberdades que o software possui. Mas esta Licena no est restrita a manuais de software; ela pode ser usada para qualquer trabalho em texto, independentemente do assunto ou se ele publicado como um livro impresso. Ns recomendamos esta Licena principalmente para trabalhos cujo propsito seja de introduo ou referncia.
APLICABILIDADE E DEFINIES
Esta Licena se aplica a qualquer manual ou outro texto que contenha uma nota colocada pelo detentor dos direitos autorais dizendo que ele pode ser distribudo sob os termos desta Licena. O "Documento"abaixo se refere a qualquer manual ou texto. Qualquer pessoa do pblico um
12
CDTC
Brasil/DF
licenciado e referida como "voc". Uma "Verso Modicada"do Documento se refere a qualquer trabalho contendo o documento ou uma parte dele, quer copiada exatamente, quer com modicaes e/ou traduzida em outra lngua. Uma "Seo Secundria" um apndice ou uma seo inicial do Documento que trata exclusivamente da relao dos editores ou dos autores do Documento com o assunto geral do Documento (ou assuntos relacionados) e no contm nada que poderia ser includo diretamente nesse assunto geral (Por exemplo, se o Documento em parte um livro texto de matemtica, a Seo Secundria pode no explicar nada de matemtica). Essa relao poderia ser uma questo de ligao histrica com o assunto, ou matrias relacionadas, ou de posies legais, comerciais, loscas, ticas ou polticas relacionadas ao mesmo. As "Sees Invariantes"so certas Sees Secundrias cujos ttulos so designados, como sendo de Sees Invariantes, na nota que diz que o Documento publicado sob esta Licena. Os "Textos de Capa"so certos trechos curtos de texto que so listados, como Textos de Capa Frontal ou Textos da Quarta Capa, na nota que diz que o texto publicado sob esta Licena. Uma cpia "Transparente"do Documento signica uma cpia que pode ser lida automaticamente, representada num formato cuja especicao esteja disponvel ao pblico geral, cujos contedos possam ser vistos e editados diretamente e sem mecanismos especiais com editores de texto genricos ou (para imagens compostas de pixels) programas de pintura genricos ou (para desenhos) por algum editor de desenhos grandemente difundido, e que seja passvel de servir como entrada a formatadores de texto ou para traduo automtica para uma variedade de formatos que sirvam de entrada para formatadores de texto. Uma cpia feita em um formato de arquivo outrossim Transparente cuja constituio tenha sido projetada para atrapalhar ou desencorajar modicaes subsequentes pelos leitores no Transparente. Uma cpia que no "Transparente" chamada de "Opaca". Exemplos de formatos que podem ser usados para cpias Transparentes incluem ASCII simples sem marcaes, formato de entrada do Texinfo, formato de entrada do LaTex, SGML ou XML usando uma DTD disponibilizada publicamente, e HTML simples, compatvel com os padres, e projetado para ser modicado por pessoas. Formatos opacos incluem PostScript, PDF, formatos proprietrios que podem ser lidos e editados apenas com processadores de texto proprietrios, SGML ou XML para os quais a DTD e/ou ferramentas de processamento e edio no estejam disponveis para o pblico, e HTML gerado automaticamente por alguns editores de texto com nalidade apenas de sada. A "Pgina do Ttulo"signica, para um livro impresso, a pgina do ttulo propriamente dita, mais quaisquer pginas subsequentes quantas forem necessrias para conter, de forma legvel, o material que esta Licena requer que aparea na pgina do ttulo. Para trabalhos que no tenham uma pgina do ttulo, "Pgina do Ttulo"signica o texto prximo da apario mais proeminente do ttulo do trabalho, precedendo o incio do corpo do texto.
13
CDTC
Brasil/DF
14
CDTC
Brasil/DF
MODIFICAES
Voc pode copiar e distribuir uma Verso Modicada do Documento sob as condies das sees 2 e 3 acima, desde que voc publique a Verso Modicada estritamente sob esta Licena, com a Verso Modicada tomando o papel do Documento, de forma a licenciar a distribuio e modicao da Verso Modicada para quem quer que possua uma cpia da mesma. Alm disso, voc precisa fazer o seguinte na verso modicada: A. Usar na Pgina de Ttulo (e nas capas, se houver alguma) um ttulo distinto daquele do Documento, e daqueles de verses anteriores (que deveriam, se houvesse algum, estarem listados na seo "Histrico do Documento"). Voc pode usar o mesmo ttulo de uma verso anterior se o editor original daquela verso lhe der permisso; B. Listar na Pgina de Ttulo, como autores, uma ou mais das pessoas ou entidades responsveis pela autoria das modicaes na Verso Modicada, conjuntamente com pelo menos cinco dos autores principais do Documento (todos os seus autores principais, se ele tiver menos que cinco); C. Colocar na Pgina de Ttulo o nome do editor da Verso Modicada, como o editor; D. Preservar todas as notas de copyright do Documento; E. Adicionar uma nota de copyright apropriada para suas prprias modicaes adjacente s outras notas de copyright; F. Incluir, imediatamente depois das notas de copyright, uma nota de licena dando ao pblico o direito de usar a Verso Modicada sob os termos desta Licena, na forma mostrada no tpico abaixo; G. Preservar nessa nota de licena as listas completas das Sees Invariantes e os Textos de Capa requeridos dados na nota de licena do Documento; H. Incluir uma cpia inalterada desta Licena; I. Preservar a seo entitulada "Histrico", e seu ttulo, e adicionar mesma um item dizendo pelo menos o ttulo, ano, novos autores e editor da Verso Modicada como dados na Pgina de Ttulo. Se no houver uma sesso denominada "Histrico"no Documento, criar uma dizendo o ttulo, ano, autores, e editor do Documento como dados em sua Pgina de Ttulo, ento adicionar um item descrevendo a Verso Modicada, tal como descrito na sentena anterior; J. Preservar o endereo de rede, se algum, dado no Documento para acesso pblico a uma cpia Transparente do Documento, e da mesma forma, as localizaes de rede dadas no Documento para as verses anteriores em que ele foi baseado. Elas podem ser colocadas na seo "Histrico". Voc pode omitir uma localizao na rede para um trabalho que tenha sido publicado pelo menos quatro anos antes do Documento, ou se o editor original da verso a que ela se rera der sua permisso; K. Em qualquer seo entitulada "Agradecimentos"ou "Dedicatrias", preservar o ttulo da 15
CDTC
Brasil/DF
seo e preservar a seo em toda substncia e m de cada um dos agradecimentos de contribuidores e/ou dedicatrias dados; L. Preservar todas as Sees Invariantes do Documento, inalteradas em seus textos ou em seus ttulos. Nmeros de seo ou equivalentes no so considerados parte dos ttulos da seo; M. Apagar qualquer seo entitulada "Endossos". Tal sesso no pode ser includa na Verso Modicada; N. No reentitular qualquer seo existente com o ttulo "Endossos"ou com qualquer outro ttulo dado a uma Seo Invariante. Se a Verso Modicada incluir novas sees iniciais ou apndices que se qualiquem como Sees Secundrias e no contenham nenhum material copiado do Documento, voc pode optar por designar alguma ou todas aquelas sees como invariantes. Para fazer isso, adicione seus ttulos lista de Sees Invariantes na nota de licena da Verso Modicada. Esses ttulos precisam ser diferentes de qualquer outro ttulo de seo. Voc pode adicionar uma seo entitulada "Endossos", desde que ela no contenha qualquer coisa alm de endossos da sua Verso Modicada por vrias pessoas ou entidades - por exemplo, declaraes de revisores ou de que o texto foi aprovado por uma organizao como a denio ocial de um padro. Voc pode adicionar uma passagem de at cinco palavras como um Texto de Capa da Frente , e uma passagem de at 25 palavras como um Texto de Quarta Capa, ao nal da lista de Textos de Capa na Verso Modicada. Somente uma passagem de Texto da Capa da Frente e uma de Texto da Quarta Capa podem ser adicionados por (ou por acordos feitos por) qualquer entidade. Se o Documento j incluir um texto de capa para a mesma capa, adicionado previamente por voc ou por acordo feito com alguma entidade para a qual voc esteja agindo, voc no pode adicionar um outro; mas voc pode trocar o antigo, com permisso explcita do editor anterior que adicionou a passagem antiga. O(s) autor(es) e editor(es) do Documento no do permisso por esta Licena para que seus nomes sejam usados para publicidade ou para assegurar ou implicar endossamento de qualquer Verso Modicada.
COMBINANDO DOCUMENTOS
Voc pode combinar o Documento com outros documentos publicados sob esta Licena, sob os termos denidos na seo 4 acima para verses modicadas, desde que voc inclua na combinao todas as Sees Invariantes de todos os documentos originais, sem modicaes, e liste todas elas como Sees Invariantes de seu trabalho combinado em sua nota de licena. O trabalho combinado precisa conter apenas uma cpia desta Licena, e Sees Invariantes Idnticas com multiplas ocorrncias podem ser substitudas por apenas uma cpia. Se houver mltiplas Sees Invariantes com o mesmo nome mas com contedos distintos, faa o ttulo de 16
CDTC
Brasil/DF
cada seo nico adicionando ao nal do mesmo, em parnteses, o nome do autor ou editor origianl daquela seo, se for conhecido, ou um nmero que seja nico. Faa o mesmo ajuste nos ttulos de seo na lista de Sees Invariantes nota de licena do trabalho combinado. Na combinao, voc precisa combinar quaisquer sees entituladas "Histrico"dos diversos documentos originais, formando uma seo entitulada "Histrico"; da mesma forma combine quaisquer sees entituladas "Agradecimentos", ou "Dedicatrias". Voc precisa apagar todas as sees entituladas como "Endosso".
COLETNEAS DE DOCUMENTOS
Voc pode fazer uma coletnea consitindo do Documento e outros documentos publicados sob esta Licena, e substituir as cpias individuais desta Licena nos vrios documentos com uma nica cpia incluida na coletnea, desde que voc siga as regras desta Licena para cpia exata de cada um dos Documentos em todos os outros aspectos. Voc pode extrair um nico documento de tal coletnea, e distribu-lo individualmente sob esta Licena, desde que voc insira uma cpia desta Licena no documento extrado, e siga esta Licena em todos os outros aspectos relacionados cpia exata daquele documento.
TRADUO
Traduo considerada como um tipo de modicao, ento voc pode distribuir tradues do Documento sob os termos da seo 4. A substituio de Sees Invariantes por tradues requer uma permisso especial dos detentores do copyright das mesmas, mas voc pode incluir tradues de algumas ou de todas as Sees Invariantes em adio s verses orignais dessas Sees Invariantes. Voc pode incluir uma traduo desta Licena desde que voc tambm inclua a verso original em Ingls desta Licena. No caso de discordncia entre a traduo e a
17
CDTC
Brasil/DF
TRMINO
Voc no pode copiar, modicar, sublicenciar, ou distribuir o Documento exceto como expressamente especicado sob esta Licena. Qualquer outra tentativa de copiar, modicar, sublicenciar, ou distribuir o Documento nula, e resultar automaticamente no trmino de seus direitos sob esta Licena. Entretanto, terceiros que tenham recebido cpias, ou direitos de voc sob esta Licena no tero suas licenas terminadas, tanto quanto esses terceiros permaneam em total acordo com esta Licena.
18
CDTC
Brasil/DF
tal como a GNU General Public License, para permitir o seu uso em software livre.
19
Parte IV
Shell Script
20
Captulo 1
21
Captulo 2
Plano de ensino
2.1 Objetivo
verb Capacitar o usurio para o aprendizado bsico dos comandos do Linux.
2.3 Pr-requisitos
Os usurios devero ser, necessariamente, funcionrios pblicos e ter conhecimentos bsicos para operar um computador com uma distribuio baseada no Debian instalada.
2.4 Descrio
O curso ser realizado na modalidade Educao a Distncia e utilizar a Plataforma Moodle como ferramenta de aprendizagem. O curso tem durao de uma semana e possui um conjunto de atividades (lies, fruns, glossrios, questionrios e outros) que devero ser executadas de acordo com as instrues fornecidas. O material didtico est disponvel on-line de acordo com as datas pr-estabelecidas em cada tpico.
2.5 Metodologia
O curso est dividido da seguinte maneira: Durao 1 semana 2 semana Descrio do Mdulo Expresses Regulares Ambiente Shell e Comandos de manipulao de caracteres
Todo o material est no formato de lies, e estar disponvel ao longo do curso. Ao nal de cada semana do curso ser disponibilizada a prova referente ao mdulo estudado anteriormente 22
CDTC
Brasil/DF
que tambm conter perguntas sobre os textos indicados. Utilize o material de cada semana e os exemplos disponibilizados para se preparar para prova.
As lies contm o contedo principal. Elas podero ser acessadas quantas vezes forem necessrias, desde que estejam dentro da semana programada. Ao nal de uma lio, voc receber uma nota de acordo com o seu desempenho. Responda com ateno s perguntas de cada lio, pois elas sero consideradas na sua nota nal. Caso sua nota numa determinada lio seja menor que 6.0, sugerimos que voc faa novamente esta lio. Ao nal do curso ser disponibilizada a avaliao referente ao curso. Tanto as notas das lies quanto a da avaliao sero consideradas para a nota nal. Todos os mdulos caro visveis para que possam ser consultados durante a avaliao nal. Aconselhamos a leitura da "Ambientao do Moodle"para que voc conhea a plataforma de Ensino a Distncia, evitando diculdades advindas do "desconhecimento"sobre a mesma. Os instrutores estaro a sua disposio ao longo de todo curso. Qualquer dvida dever ser enviada ao frum. Diariamente os monitores daro respostas e esclarecimentos.
2.6 Programa
O curso de CVS oferecer o seguinte contedo: Expresses regulares; Ambiente Shell, Linhas de comando, Caracteres de remoo, redirecionamento e ambiente; A famlia grep, Passagens de parmetros; Comando cut, Comando tr, Usando separadores, Comando condicionais; O comando eval, O trap no atrapalha, O comando getopts; Comando test, Simplicaes dos comandos condicionais; Comandos de Loop; Um pouco mais de Loops e matemtica; O comando tput; Funes; Variveis do Shell; Named Pipes.
2.7 Avaliao
Toda a avaliao ser feita on-line. Aspectos a serem considerados na avaliao: Expresses Regulares; 23
CDTC
Brasil/DF
Ambiente Shell; Comandos de manipulao de caracteres; Capacidade de pesquisa e abordagem criativa na soluo dos problemas apresentados. Instrumentos de avaliao: Participao ativa nas atividades programadas. Avaliao ao nal do curso. O participante far vrias avaliaes referente ao contedo do curso. Para a aprovao e obteno do certicado o participante dever obter nota nal maior ou igual a 6.0 de acordo com a frmula abaixo: Nota Final = ((ML x 7) + (AF x 3)) / 10 = Mdia aritmtica das lies AF = Avaliaes
2.8 Bibliograa
Site http://aurelio.net/shell/ Site: http://www.ic.unicamp.br/ celio/mc514/bash/bash.html
24
Captulo 3
Introduo
Sejam bem vindos ao curso de Bash Bsico! O curso tem durao de apenas duas semanas e consiste na leitura de alguns livros e lies e, ao trmino delas, realizar algumas avaliaes. Todas essas atividades valem pontuao. Para um bom aproveitamento do curso importante que haja entrosamento com os materiais, os fruns e os tutores. Seja participativo, questione e tire suas dvidas. O material didtico do prof. Jlio Neves e de fato no h nada melhor que aprender brincando. interessante que j esteja instalado o Linux e que deixe o terminal sempre aberto. Assim facilita acompanhar o raciocnio da leitura. Qualquer dvida quanto ao comando pode ser resolvida digitando no Shell: $ man nomedocomando ou ainda discutindo concosco no frum. Assim aprendemos juntos a funcionalidade de cada um. Bom trabalho!
25
Captulo 4
Expresses Regulares
4.1 Introduo
Uma Expresso Regular (ER) um mtodo formal de se especicar um padro de texto. uma composio de smbolos, caracteres com funes especiais, chamados "metacaracteres"que, agrupados entre si e com caracteres literais, formam uma seqncia, uma expresso. Essa expresso testada em textos e retorna sucesso caso este texto obedea exatamente a todas as suas condies. Diz-se que o texto "casou"com a expresso. A ERs servem para se dizer algo abrangente de forma especca. Denido o padro de busca, tem-se uma lista (nita ou no) de possibilidades de casamento. Em um exemplo rpido, [rgp]ato pode casar "rato", "gato"e "pato"]. As ERs so teis para buscar ou validar textos variveis como: data; horrio; nmero IP; endereo de e-mail; endereo de Internet; declarao de uma funo (); dados na coluna N de um texto; dados que esto entre <tags></tags>; nmero de telefone, RG, CPF, carto de crdito. Vrios editores de texto e linguagens de programao tm suporte a ERs, ento, o tempo investido em seu aprendizado recompensado pela larga variedade de aplicativos onde ele pode ser praticado.
CDTC
Brasil/DF
comando grep tem o seguinte formato: grep palavra arquivo Vamos utilizar como exemplo o arquivo /etc/passwd, que a base de usurios de um sistema UNIX/Linux. Vale a pena, antes, vericar como que se constitui esse arquivo dando o comando: $cat /etc/passwd Observa-se que sero obtidas vrias linhas, onde cada um se refere a um usurio diferente. E cada linha possui o seguinte formato: login : senha : UID : GID : Nome completo : Diretrio $HOME : shellz Voltando ao grep. Para "pescar"somente a linha do usurio root faremos: $ grep root /etc/passwd root:x:0:0:root:/root:/bin/bash
4.3 Os Metacaracteres
Cada metacaracteres uma ferramenta que tem uma funo especca. Servem para dar mais poder s pesquisas, informando padres e posies impossveis de se especicar usando somente caracteres normais. Os metacaracteres so pequenos pedacinhos simples, que agrupados entre si ou com caracteres normais formam algo maior, uma expresso. O importante compreender bem cada um individualmente, e depois apenas l-los em seqncia.
Metacaracteres Representantes
So aqueles cuja funo representar um ou mais caracteres. Ponto . Lista [...] Lista Negada [^...]
O ponto
O ponto nosso curinga solitrio, que est sempre procura de um casamento no importa com quem seja. Pode ser um nmero, uma letra, um TAB, um , o que vier ele traa, pois o ponto casa qualquer coisa. Exemplos: "n.o"casaria: no, nao, ... 27
CDTC
Brasil/DF
Bem mais exigente que o ponto, a lista no casa com qualquer um. Ela sabe exatamente o que quer, e nada diferente daquilo, a lista casa com quem ela conhece. Toda "lista"(os colchetes e seu contedo) vale para apenas uma posio, um caractere, por maior que seja. Exemplos: n[a]o no, nao, ... [Tt]eclado teclado, Teclado, .... 12[:. ]45 12:45, 12 45, 12.45, ... A lista de certa forma exigente. Sendo assim: Evite Prera: [0123456789] [0-9] [0-9][0-9]:[0-9][0-9] [012][0-9]:[0-5][0-9] [A-z] [A-Za-z]
Lista negada
A lista negada exatamente igual lista, podendo ter caracteres literais, intervalos e classes POSIX. Tudo o que se aplica a lista normal, se aplica negada tambm. A nica diferena que ela possui lgica inversa, ou seja, ela casar com qualquer coisa, fora os componentes listados. Observe que a diferena em sua notao que o primeiro caractere da lista um circunexo, ele indica que esta uma lista negada. Ento, se [0-9] so nmeros, [^\0-9] qualquer coisa fora nmeros. Pode ser letras, smbolos, espao em branco, qualquer coisa menos nmeros. Porm, ao iniciar o circunexo (^) fora das chaves possui outro signicado diferente: simboliza o incio de uma linha. Mas tem de ser alguma coisa. S porque ela uma lista negada isso no signica que ela pode casar "nada". Exemplos: [A-Z^] casa maisculas e o circunexo e [^A-Z^]casa tudo fora isso. Como mandam as regras da boa escrita, sempre aps caracteres de pontuao como a vrgula ou o ponto, devemos ter um espao em branco os separando do resto do texto. Ento, vamos procurar por qualquer coisa que no o espao aps a pontuao: [:;,.!?][^ ]
CDTC
Brasil/DF
chaves Opcional til para procurar palavras no singular e plural e pode ser tornar opcionais caracteres e metacaracteres. Exemplos: Expresso Casa com Ondas? Onda Ondas Senadora? Senador Senadora [BFM]?ala ala Bala Fala Mala Asterisco Pode aparecer em qualquer quantidade. O curinga .* o tudo e o nada, qualquer coisa. Exemplos: 6*0 0, 60, 660, 6660, ..., 666666666660, ... bi*p bp, bip, biip, biiip, biiiip... b[ip]* b, bi, bip, biipp, bpipipi, biiiiip ... Mais Tem funcionamento idntico ao do asterisco, tudo o que vale para um, se aplica ao outro. A nica diferena que o mais (+) no opcional, ento a entidade anterior deve casar pelo menos uma vez, e pode ter vrias. Sua utilidade quando queremos no mnimo uma repetio. Exemplos: 6+0 60, 660, 6660, ..., 666666660, ... bi+p bip, biip, biiip, biiiip... b[ip]+ bi, bip, biipp, bpipipi, biiiiip, bppp, ... Chaves As chaves so a soluo para uma quanticao mais controlada, onde se pode especicar exatamente quantas repeties se quer da entidade anterior. Colocando um nmero entre chaves " ", indica-se uma quantidade de repeties do caractere (ou metacaractere) anterior. As chaves so precisas podendo especicar um nmero exato, um mnimo, um mximo, ou uma faixa numrica. Elas, inclusive, simulam o *, + e ?. Exemplos: n,m signica de n at m vezes, assim algo como 61,4 casa 6, 66, 666 e 6666. S, nada mais que isso. 0,1 zero ou 1 (igual ao opcional) 0, zero ou mais (igual ao asterisco) 1, um ou mais (igual ao mais) 3 exatamente
29
CDTC
Brasil/DF
4.5.1
Circunexo
Este metacaractere (do tipo de posicionamento por representar uma posio especca da linha) simboliza o incio de uma linha. tambm o marcador de lista negada, mas apenas dentro da lista (e no comeo), fora dela ele a ncora que marca o incio de uma linha, veja:
^[0-9]
signica que casa com uma linha comeando com qualquer algarismo. O inverso disso seria:
^[^0-9]
4.5.2
Cifro - o m
Este similar e complementar ao circunexo, pois representa o m de uma linha e s vlido no nal de uma expresso regular. Quando demos o comando: $ grep bash$ /etc/passwd signica que procuramos pela palavra "bash"no nal da linha, ou ainda, a palavra "bash"seguida de um m de linha. Esse cifro o mesmo caractere que utilizado para identicar as variveis do shell, como $PWD e $HOME. Para evitar possveis problemas com a expanso de variveis, preciso "proteger"a expresso regular passada ao grep. A proteo feita colocando-se a ER entre aspas simples fazendo: $ grep bash$ /etc/passwd Veja outros exemplos: 30
CDTC
Brasil/DF
4.5.3
Borda - a limtrofe
A borda marca os limites de uma palavra, ou seja, onde ela comea e/ou termina. muito til para casar palavras exatas, e no partes de palavras. Palavra aqui um conceito que engloba apenas letras, nmeros e o sublinhado:
[A-Za-z0-9_]
Veja os exemplos: Veja como se comportam as ERs nas palavras dia, diafragma, radial, melodia e bom-dia!: dia - - - dia, diafragma, radial, melodia, bom-dia! \bdia - - - dia, diafragma, bom-dia! dia\b - - - dia, melodia, bom-dia! \bdia\b dia, bom-dia!
4.6
Outros metacaracteres
Vamos ver outros metacaracteres, que tm funes especcas e no relacionadas entre si, portanto no podem ser agrupados em outra classe fora a tradicional "outros". Mas ateno, isso no quer dizer que eles so inferiores, pelo contrrio, o poder das ERs multiplicado com seu uso e um mundo de possibilidades novas se abre a sua frente. So eles: escape \ ou | grupo () retrovisor /n
CDTC
Brasil/DF
"Escapando"o Caractere: Lua\* casa com Lua* Isto , a contrabarra (\) "escapa"qualquer metacaractere, tirando todos os seus poderes. O escape to poderoso que pode escapar a si prprio! O \ casa uma barra invertida \ literal. Ento, agora que sabemos muito sobre ERs, que tal uma expresso para casar um nmero de RG? Lembre-se que ele tem o formato n.nnn.nnn-n, fcil! [0-9]\.[0-9]{3}\.[0-9]{3}-[0-9] O \* = [*] = asterisco literal Ironia -> O escape escapa o escape, escapando-se a si prprio, simultaneamente.
4.7.2 Ou
Para procurar por uma coisa ou outra, deve-se usar o pipe "|" e delimitar as opes com os parnteses "( )". muito comum em uma posio especca de nossa Expresso Regular (ER) termos mais de uma alternativa possvel, por exemplo, ao casar um cumprimento amistoso, podemos ter uma terminao diferente para cada parte do dia: boa-tarde|boa-noite O ou serve para esses casos em que precisamos dessas alternativas. Essa ER se l: "ou boa-tarde, ou boa-noite", ou seja "ou isso ou aquilo". Lembre que a lista tambm uma espcie de ou (|), mas apenas para uma letra, ento:
4.7.3 Grupo
Assim como artistas famosos e personalidades que conseguem arrastar multides, o grupo tem o dom de juntar vrios tipos de sujeitos em um mesmo local. Dentro de um grupo podemos ter um ou mais caracteres, metacarateres e inclusive outros grupos. Como em uma expresso matemtica, os parnteses denem um grupo e seu contedo pode ser visto como um bloco na expresso. Todos os metacaracteres quanticadores que vimos anteriormente podem ter seu poder ampliado pelo grupo, pois ele lhes d mais abrangncia. E o ou, pelo contrrio, tem sua abrangncia limitada pelo grupo, e pode parecer estranho, mas essa limitao que lhe d mais poder. Em um exemplo simples, (ai)+ agrupa a palavra ai e esse grupo est quanticado pelo mais (+). Isso quer dizer que casamos vrias repeties da palavra, como ai, aiai, aiaiai, ... E assim podemos agrupar tudo o 32
CDTC
Brasil/DF
que quisermos, literais e metacaracteres, e quantic-los: (ha!)+ ha!, ha!ha!, ha!ha!ha!, ... (\.[0-9]){3} .0.6.2, .2.8.9, .6.6.6, ... (www )?zz\.com www.zz.com, zz.com E em especial, nosso amigo ou ganha limites ou seu poder cresce: boa-(tarde|noite) boa-tarde, boa-noite #(|n\.|nm) 6 # 6, n. 6, nm 6 (in|con)?certo incerto, concerto, certo Podemos criar subgrupos tambm, ento imagine que voc esteja procurando o nome de um supermercado em uma listagem e no sabe se este um mercado, supermercado ou um hipermercado. (super|hiper)mercado Consegue casar as duas ltimas possibilidades, mas note que nas alternativas super e hiper temos um trecho per comum aos dois, ento podamos "alternativizar"apenas as diferenas su e hi: (su|hi)permercado Precisamos tambm casar apenas o mercado sem os aumentativos, ento temos de agruplos e torn-los opcionais: ((su|hi)per)?mercado Ei! E se tivesse minimercado tambm? (mini|(su|hi)per)?mercado
4.7.4 Retrovisor
(quero)- \1 Mas esse \1 no o tal do escape? Pois , lembra que o escape (\) servia para tirar os poderes do metacaractere seguinte. Ento, a essa denio agora inclumos: a no ser que este prximo caractere seja um nmero de 1 a 9, ento estamos lidando com um retrovisor. Notou o detalhe? Podemos ter no mximo 9 retrovisores por ER, ento \10 o retrovisor nmero 1 seguido de um zero. O verdadeiro poder do retrovisor quando no sabemos exatamente qual texto o grupo casar. Vamos estender o quero do exemplo anterior para "qualquer palavra": http://www.redhat.com/docs/manuals/linux/RHL-7.2-Manual/custom-guide/rescuemode.html ([A33
CDTC Za-z]+)-\1
Brasil/DF
Viu o poder dessa ER? Ela casa palavras repetidas separadas por um trao, como o prprio quero-quero, e mais: bate-bate, come-come, etc. Mas, e se tornssemos o trao opcional?
([A-Za-z]+)-?\1
Com uma modicao pequena, fazemos um minicorretor ortogrco para procurar por palavras repetidas como estas em um texto:
([A-Za-z]+) \1
Mas, lembre-se que procuramos por palavras inteiras e no apenas trechos delas, ento precisamos usar as bordas para completar nossa ER:
\b([A-Za-z]+) \1\b
http://www.redhat.com/docs/manuals/linux/RHL-7.2-Manual/custom-guide/rescuemode.html Como j dito, podemos usar no mximo nove retrovisores. Vamos ver uns exemplos com mais de um de nossos amigos novos: (lenta)(mente) \2 \1 lentamente mente lenta ((band)eira)nte \1 \2a bandeirante bandeira banda in(d)ol(or) sem \1 \2 indolor sem dor ((((a)b)c)d)-1 = \1, \2, \3, \4 abcd-1 = abcd,abc,ab,a Repare que numeram-se retrovisores contando os grupos da esquerda para a direita. Ao usar um (grupo) qualquer, voc ganha um brinde, e muitas vezes nem sabe. O brinde o trecho de texto casado pela ER que est no grupo, que ca guardado em um cantinho especial e pode ser usado em outras partes da mesma ER. Ento, o retrovisor \1 uma referncia ao texto casado do primeiro grupo, nesse caso quero, cando, no m das contas, a expresso que queramos. O retrovisor pode ser lembrado tambm como um link ou um ladro, pois copia o texto do grupo. Como o nome diz, retrovisor porque ele "olha pra trs", para buscar um trecho j casado. Isso muito til para casar trechos repetidos em uma mesma linha. Veja bem, o texto, e no a ER. Como exemplo, em um texto, procuramos quero-quero. Podemos procurar literalmente por queroquero, mas assim no tem graa, vamos usar o grupo e o retrovisor para fazer isso.
34
Captulo 5
Parte I
5.1 Dilogo
Dilogo entre um Linuxer e um empurrador de mouse: - Quem o Bash? - O Bash o lho mais novo da famlia Shell. - P cara! Ests a m de me deixar maluco? Eu tinha uma dvida e voc me deixa com duas! No, maluco voc j h muito tempo. Desde que se decidiu a usar aquele sistema operacional que voc tem que dar dez boots por dia e no tem domnio nenhum sobre o que est acontecendo no seu computador. Mas deixa isso pr l, vou te explicar o que Shell e os componentes de sua famlia e ao nal da explanao voc dir: "Meu Deus do Shell! Porque eu no optei pelo Linux antes?".
35
CDTC
Brasil/DF
. Neste grco d para ver que a camada de hardware a mais profunda e formada pelos componentes fsicos do seu computador. Envolvendo esta, vem a camada do kernel que o cerne do Linux, seu ncleo, quem coloca o hardware para funcionar fazendo seu gerenciamento e controle. Os programas e comandos que envolvem o kernel, dele se utilizam para realizar as tarefas aplicativas para que foram desenvolvidos. Fechando tudo isso vem o Shell que leva este nome porque em ingls, Shell signica concha, carapaa, isto , ca entre o usurio e o sistema operacional, de forma que tudo que interage com o sistema operacional, tem que passar pelo seu crivo. http://www.redhat.com/docs/manuals/linux/RHL-7.2-Manual/custom-guide/rescuemode.html
36
CDTC
Brasil/DF
Shell (csh) Desenvolvido por Bill Joy da Berkley University o Shell mais utilizado em ambientes *BSD e Xenix. A estruturao de seus comandos bem similar da linguagem C. Seu grande pecado foi ignorar a compatibilidade com o sh, partindo por um caminho prprio. Alm destes Shells existem outros, mas, neste curso, ser abordado somente sobre os trs primeiros tratando-os genericamente por Shell e assinalando as especicidades de cada um que porventura hajam.
Ateno: Quando foi dito que o ltimo campo do /etc/passwd informa ao sistema qual o Shell que o usurio receber ao se "logar", para ser interpretado ao p-da-letra, isto , se neste campo do seu registro estiver prog, a pessoa ao acessar o sistema receber a tela de execuo do programa prog e ao terminar a sua execuo ganhar imediatamente um logout. Imagine o quanto se pode incrementar a segurana com este simples. artifcio.
Comando
Quando uma linha digitada no prompt do Linux, ela dividida em pedaos separados por espao em branco: o primeiro pedao o nome do programa que ter sua existncia pesquisada; identica em seguida, nesta ordem, opes/parmetros, redirecionamentos e variveis. Quando o programa identicado existe, o Shell verica as permisses dos arquivos envolvidos (inclusive o prprio programa), dando um erro caso voc no esteja credenciado a executar esta tarefa.
Atribuio
Se o Shell encontra dois campos separados por um sinal de igual ()= sem espaos em branco 37
CDTC
Brasil/DF
entre eles, identica esta seqncia como uma atribuio. Exemplos: $ ls linux linux Neste exemplo, o Shell identicou o ls como um programa e o linux como um parmetro passado para o programa ls. $ valor=1000 Neste caso, por no haver espaos em branco (j d para notar que o branco um dos caracteres reservados) o Shell identicou uma atribuio e colocou 1000 na varivel valor. Jamais Faa: $ valor = 1000 bash: valor: not found Neste caso, o Bash achou a palavra valor isolada por brancos e julgou que voc estivesse mandando executar um programa chamado valor, para o qual estaria passando dois parmetros: = e 1000.
Resoluo de Redirecionamentos
Aps identicar os componentes da linha que voc teclou, o Shell parte para a resoluo de redirecionamentos. O Shell tem incorporado ao seu elenco de vantagens o que chamamos de redirecionamento, que pode ser de entrada (stdin), de sada (stdout) ou dos erros (stderr), conforme ser explicado a seguir.
Substituio de Variveis
Neste ponto, o Shell verica se as eventuais variveis (parmetros comeados por $), encontradas no escopo do comando, esto denidas e as substitui por seus valores atuais.
38
CDTC
Brasil/DF
Apstrofo ou plic ()
Quando o Shell v uma cadeia de caracteres entre apstrofos ('), ele tira os apstrofos da cadeia e no interpreta seu contedo. $ ls linux* linuxmagazine $ ls linux* bash: linux* no such le or directory No primeiro caso, o Shell "expandiu"o asterisco e descobriu o arquivo linuxmagazine para listar. No segundo, os apstrofos inibiram a interpretao do Shell e veio a resposta que no existe o arquivo linux*.
Aspas (")
Exatamente igual ao apstrofo exceto que, se a cadeia entre aspas contiver um cifro ($), uma crase (`), ou uma barra invertida (\), estes caracteres sero interpretados pelo Shell. No precisa se preocupar, no foi dado exemplos do uso das aspas por que voc ainda no conhece o cifro($) nem a crase (`). Daqui para frente veremos com muita constncia o uso destes 39
CDTC
Brasil/DF
Ateno: Como j haviamos lhe dito, o Shell resolve a linha e depois manda o comando para a execuo. Assim, se voc redirecionar a sada de um arquivo 40
CDTC
Brasil/DF
para ele prprio, primeiramente o Shell "esvazia"este arquivo e depois manda o comando para execuo, desta forma voc acabou de perder o contedo do seu arquivo. Com isso d para notar que o (maior maior) serve para inserir texto no nal do arquivo.
CDTC
Brasil/DF
mesmo comando, recebemos somente o prompt na tela. Quando listamos o contedo do arquivo para o qual foi redirecionada a Sada de Erro Padro, vimos que a mensagem de erro tinha sido armazenada nele. Faa este teste. Dica 2: - Quem esse tal de /dev/null? - Em Unix existe um arquivo fantasma. Chama-se /dev/null. Tudo que mandado para este arquivo some, assemelha-se a um Buraco Negro. No caso do exemplo, como no nos interessava guardar a possvel mensagem de erro oriunda do comando rm, redirecionamosa para este arquivo. interessante notar que estes caracteres de redirecionamento so cumulativos, isto , se no exemplo anterior zssemos: $ ls naoexiste 2 arquivodeerros a mensagem de erro oriunda do ls seria anexada ao nal de arquivodeerros.
CDTC
Brasil/DF
cada arquivo (-i de interactive), e nalmente a opo -n serve para dizer ao ftp para ele no solicitar o usurio e sua senha, pois esses sero informados pela instruo especca (user). 2. Quando foi usado o mftp, estava dizendo o seguinte para o intrprete: "Shell, no faa nada a partir daqui at encontrar o label mftp. Voc no entenderia nada, j que so instrues especcas do comando ftp e voc no entende nada de =ftp=". Se fosse s isso seria simples, mas pelo prprio exemplo d para ver que existem duas variveis ($Usurio e $Senha), que o Shell resolver antes do redirecionamento. Mas a grande vantagem desse tipo de construo que ela permite que comandos tambm sejam interpretados dentro do escopo do here document, o que tambm contraria o que foi dito. Depois ser explicado como isso funciona. Agora no d, pois est faltando ferramenta. 1. O comando user do repertrio de instrues do ftp e serve para passar o usurio e a senha que haviam sido lidos em uma rotina anterior a esse fragmento de cdigo e colocados, respectivamente, nas duas variveis: $Usurio e $Senha. 2. . O binary outra instruo do ftp, que serve para indicar que a transferncia de arquivoremoto ser feita em modo binrio, isto , o contedo do arquivo no ser interpretado para saber se est em ASCII, EBCDIC, ... 3. O get arquivoremoto diz ao ftp para pegar esse arquivo em hostremoto e traz-lo para o nosso host local. Se fosse para mandar o arquivo, usaramos o comando put. Ateno: Um erro muito freqente no uso de labels (como o mftp do exemplo anterior) causado pela presena de espaos em branco antes ou aps o mesmo. Fique muito atento quanto a isso, por que este tipo de erro cria problemas no programador, at que seja detectado. Lembre-se: um label que se preze tem que ter uma linha inteira s para ele.
CDTC
Brasil/DF
Esta linha de comandos manda a listagem do arquivo /etc/passwd para a entrada do comando sort. Este a classica e manda-a para o lp que o gerenciador do spool de impresso.
CDTC
Brasil/DF
/etc/ /home/meudir Neste exemplo, listamos o nome do diretrio corrente com o comando pwd, mudamos para o diretrio /etc, novamente listamos o nome do diretrio e, nalmente, voltamos para o diretrio onde estava anteriormente (cd -), listando seu nome. Repare que foi colocado o ponto-e-vrgula (;) de todas as formas possveis para mostrar que no importa se existem espaos em branco antes ou aps este caractere. Finalmente, vamos ver o caso dos parnteses. Veja s o caso a seguir, bem parecido com o exemplo anterior: $ (pwd ; cd /etc ; pwd;) /home/meudir /etc/ $ pwd /home/meudir - Quequeiiisso minha gente? Eu estava no /home/meudir, mudei para o /etc, constatei que estava neste diretrio com o pwd seguinte, e quando o agrupamento de comandos terminou, eu vi que continuava no /etc/meudir, como se eu nunca houvesse sado de l! - Ih! Ser que tem coisa de mgico a? - T me estranhando, rapaz? No nada disso! O interessante do uso de parnteses que ele invoca um novo Shell para executar os comandos que esto no seu interior. Desta forma, realmente fomos para o diretrio /etc, porm quando todos os comandos dentro dos parnteses foram executados, o novo Shell que estava no diretrio /etcShell anterior cujo diretrio corrente era /home/meudir. Faa outros testes usando cd, e ls para voc rmar o conceito. Agora que j conhecemos estes conceitos veja s este exemplo: $ mail suporte FIM http://www.redhat.com/docs/manuals/linux/RHL-7.2-Manual/custom-guide/rescuemode.html >Ola suporte, hoje as date"+%hh:mm" >ocorreu novamente aquele problema >que eu havia reportado por >telefone. Conforme seu pedido >ai vai uma listagem dos arquivos >do diretorio: >ls -l >Abracos a todos. >FIM Finalmente, agora, temos conhecimento para mostrar o que havamos conversado sobre here document. Os comandos entre crases () sero priorizados e, portanto, o Shell os executar antes da instruo mail. Quando o suporte receber o e-mail, ver que os comandos date e ls foram executados imediatamente antes do comando mail, recebendo ento uma fotograa do ambiente no momento em que a correspondncia foi enviada.
45
CDTC
Brasil/DF
O prompt primrio default do Shell, como vimos, o cifro ($), porm o Shell usa o conceito de prompt secundrio, ou de continuao de comando que enviado para a tela quando h uma quebra de linha e a instruo no terminou. Esse prompt, representado por um sinal de maior (>), que vemos precedendo a partir da 2 linha do exemplo. Para nalizar e bagunar tudo, devo dizer que existe uma construo mais moderna que vem sendo utilizada como forma de priorizao de execuo de comandos, tal qual as crases (). So as construes do tipo $(cmd), onde cmd um (ou vrios) comando que ser(o) executado(s) com prioridade em seu contexto. Assim sendo, o uso de crases () ou construes do tipo $(cmd) servem para o mesmo m, porm para quem trabalha com sistemas operacionais de diversos fornecedores (multiplataforma), aconselho o uso das crases j que o $(cmd) no foi portado para todos os sabores de Shell. Aqui dentro do Botequim, usarei ambas as formas, indistintamente. Vejamos novamente o exemplo dado para as crases sob esta nova tica: $ echo Existem $(who | grep wc -l) usurios conectados Existem 8 usurios conectados Veja s este caso: $ Arqs=ls $ echo $Arqs ls Neste exemplo, eu z uma atribuio (=) e executei uma instruo. O que eu queria era que a varivel $Arqs, recebesse a sada do comando ls. Como as instrues de um script so interpretadas de cima para baixo e da esquerda para a direita, a atribuio foi feita antes da execuo do ls. Para fazer o que desejamos necessrio que eu priorize a execuo deste comando em detrimento da atribuio e isto pode ser feito de qualquer uma das maneiras a seguir: $ Arqs=ls ou: $ Arqs=$(ls) Para encerrar este assunto, vamos ver s mais um exemplo. Digamos que eu queira colocar dentro da varivel $Arqs a listagem longa (ls -l) de todos os arquivos comeados por arq e seguidos de um nico caractere (?). Eu deveria fazer: $ Arqs=$(ls -l arq?) ou: $ Arqs=ls -l arq? Mas veja:
46
CDTC
Brasil/DF
$ echo $Arqs -rw-rr 1 jneves jneves 19 May 24 19:41 arq1 -rw-rr 1 jneves jneves 23 May 24 19:43 arq2 -rw-rr 1 jneves jneves 1866 Jan 22 2003 arql - P, saiu tudo embolado! - Pois cara, como eu j te disse, se voc deixar o Shell "ver"os espaos em branco, sempre que houver diversos espaos juntos, eles sero trocados por apenas um. Para que a listagem saia bonitinha, necessrio proteger a varivel da interpretao do Shell, assim: $ echo "$Arqs" -rw-rr 1 jneves jneves 19 May 24 19:41 arq1 -rw-rr 1 jneves jneves 23 May 24 19:43 arq2 -rw-rr 1 jneves jneves 1866 Jan 22 2003 arql - Olhe, amigo, v treinando esses exemplos, porque, quando nos encontrarmos novamente, vou lhe explicar uma srie de instrues tpicas de programao Shell. Tchau! Ahh! S mais uma coisinha que eu ia esquecendo de lhe dizer. Em Shell, o "jogo da velha"(#) usado quando desejamos fazer um comentrio. $ exit # pede a conta ao garcon
47
Captulo 6
Parte II
6.1 Dilogo
- Garom! Traz um "chops"e dois "pastel". O meu amigo hoje no vai beber por que ele nalmente esta sendo apresentado a um verdadeiro sistema operacional e ainda tem muita coisa a aprender! - E ento, amigo, t entendendo tudo que te expliquei at agora? - Entendendo eu t, mas no vi nada prtico nisso... - Calma rapaz, o que te falei at agora, serve como base ao que h de vir daqui pra frente. Vamos usar estas ferramentas que vimos para montar programas estruturados, que o Shell permite. Voc ver porque at na TV j teve programa chamado "O Shell o Limite". - Para comear vamos falar dos comandos da famlia grep. - grep? No conheo nenhum termo em ingls com este nome... - claro, grep um acrnimo Global Regular Expression Print, que usa expresses regulares para pesquisar a ocorrncia de cadeias de caracteres na entrada denida (se bem que h uma lenda sobre como este comando foi nomeado: no editor de textos "ed", o av do "vim", o comando usado para buscas era g/_expressao regular_/p, ou no ingls g/_re_/p.). Por falar em expresses regulares (ou regexp), o Aurlio Marinho Jargas tem todas as dicas em sua pgina (inclusive tutorias) que abordam o tema. Se voc est mesmo a m de aprender a programar em Shell, Perl, Python, ... Acho bom voc ler estes artigos para te ajudar no que est para vir. Pergunta: O grep um aplicativo para linha de comando que faz buscas no contedo dos arquivos. Aceita expresses regulares e ao utiliz-las no grep recomendado utilizar escapes " para caracteres como "*"para que o bash no o entenda como um curinga para nomes de arquivos. A denio dada est correta?
CDTC
Brasil/DF
Pesquisando na sada de comando: $ who | grep Pelegrino No 1 exemplo, o mais simples, procurei a palavra rafael em qualquer lugar do arquivo /etc/passwd. Se quisesse procur-la como um login name, isto , somente no incio dos registros deste arquivo, eu deveria fazer: $ grep '^rafael /etc/passwd E para que serve este circunexo e os apstrofos? O circunexo (^), se voc tivesse lido os artigos anteriores sobre expresses regulares que te falei, saberia que servem para limitar a pesquisa ao incio de cada linha, e os apstrofos () servem para o Shell no interpretar este circunexo, deixando-o passar inclume para o comando grep. O grep aceita como entrada, a sada de outro comando redirecionado por um pipe (isto muito comum em Shell e um tremendo acelerador de execuo de comando j que atua como se a sada de um programa fosse guardada em disco e o segundo programa lesse este arquivo gerado), desta forma, no 3 exemplo, o comando who listou as pessoas "logadas"na mesma mquina que voc (no se esquea jamais: o Linux multiusurio) e o grep foi usado para vericar se o Pelegrino estava trabalhando ou "coando".
O grep pode ou no usar expresses regulares simples, porm no caso de no us-las, o fgrep melhor, por ser mais rpido; O egrep ("e"de extended, extendido) muito poderoso no uso de expresses regulares. Por ser o mais lento da famlia, s deve ser usado quando for necessria a elaborao de uma expresso regular no aceita pelo grep; O fgrep ("f"de fast, rpido, ou de "le", arquivo) como o nome diz o rapidinho da famlia, executa o servio de forma muito veloz (por vezes cerca de 30% mais veloz que o grep e 50% mais que o egrep), porm no permite o uso de expresses regulares na pesquisa. Ateno: Tudo que foi dito acima sobre velocidade, s se aplica famlia de comandos grep do Unix. No Linux o grep sempre mais veloz, j que os outros dois (fgrep e egrep) so scripts em Shell que chamam o primeiro. 49
CDTC
Brasil/DF
Agora que voc j conhece as diferenas entre os membros da famlia, me diga: o que voc acha dos trs exemplos que eu dei antes das explicaes? - Eu achei que o fgrep resolveria o teu problema de forma mais veloz do que o grep. - Perfeito! T vendo que voc est atento! Est entendendo tudo que estou te explicando! Ento vamos ver mais exemplos para clarear de vez as diferenas de uso dos membros da famlia.
50
CDTC
Brasil/DF
Vamos ver mais um. Sabemos que as quatro primeiras posies possveis de um ls -l de um arquivo comum (arquivo comum! No diretrio, nem link, nem...) devem ser:
. Assim sendo, para descobrir todos os arquivos executveis em um determinado diretrio eu deveria fazer: $ ls -la | egrep '^-..(x|s) -rwxr-xr-x 1 root root 2875 Jun 18 19:38 rc -rwxr-xr-x 1 root root 857 Aug 9 22:03 rc.local -rwxr-xr-x 1 root root 18453 Jul 6 17:28 rc.sysinit Onde novamente usamos o circunexo (^) para limitar a pesquisa ao incio de cada linha, ento as linhas listadas sero as que comeam por um trao (-), seguido de qualquer coisa (o ponto quando usado como uma expresso regular signica qualquer coisa), novamente seguido de qualquer coisa, vindo a seguir um x ou um s. Obteramos o mesmo resultado se zssemos: $ ls -la | grep '^-..[xs]' e agilizaramos a pesquisa.
51
CDTC
Brasil/DF
nome do lbum^intrprete1~nome da msica1:..:intrprete~nome da msica isto , o nome do lbum ser separado por um circunexo (^) do resto do registro, que formado por diversos grupos compostos pelo intrprete de cada msica do CD e a respectiva msica interpretada. Estes grupos so separados entre si por dois-pontos (:) e internamente, o intrprete ser separado por um til (~) do nome da msica. Eu quero escrever um programa que chamado musinc, incluir registros no meu arquivo musicas. Eu passarei o contedo de cada lbum como parmetro na chamada do programa fazendo assim: $ musinc "lbum^interprete~musica:interprete~musica:..." Desta forma o programa musinc estar recebendo os dados de cada lbum como se fosse uma varivel. A nica diferena entre um parmetro recebido e uma varivel que os primeiros recebem nomes numricos (nome numrico ca muito esquisito, n? O que quis dizer que seus nomes so formados por um e somente um algarismo), isto $1, $2, $3, ..., $9. Vamos, antes de tudo, fazer um teste: Exemplos $ cat teste #!/bin/bash # Programa para testar passagem de parametros echo "1o. parm -> $1" echo "2o. parm -> $2" echo "3o. parm -> $3" Vamos execut-lo: $ teste passando parametros para testar bash: teste: cannot execute Ops! Esqueci-me de torn-lo executvel. Vou faz-lo de forma a permitir que todos possam execut-lo e em seguida vou test-lo: $ chmod 755 teste $ teste passando parametros para testar 1o. parm -> passando 2o. parm -> parametros 3o. parm -> para Repare que a palavra testar, que seria o quarto parmetro, no foi listada. Isto deu-se justamente porque o programa teste s listava os trs primeiros parmetros. Vamos execut-lo de outra forma: $ teste "passando parametros"para testar 1o. parm -> passando parametros 52
CDTC
Brasil/DF
2o. parm -> para 3o. parm -> testar As aspas no deixaram o Shell ver o espao em branco entre as palavras e considerou-as um nico parmetro.
. Exemplos Vamos alterar o programa teste para usar as variveis que acabamos de ver. Vamos faz-lo assim: $ cat teste #!/bin/bash # Programa para testar passagem de parametros (2a. Versao) echo O programa $0 recebeu $# parametros echo "1o. parm -> $1" echo "2o. parm -> $2" echo "3o. parm -> $3" echo Todos de uma s acada $* t : Repare que antes das aspas eu usei uma barra invertida para escond-las da interpretao do Shell (se no usasse as contrabarras as aspas no apareceriam). Vamos execut-lo: $ teste passando parametros para testar O programa teste recebeu 4 parametros 1o. parm -> passando 2o. parm -> parametros 3o. parm -> para Todos de uma s "tacada": passando parmetros para testar Conforme eu disse, os parmetros recebem nmeros de 1 a 9, mas isso no signica que no posso usar mais de 9 parmetros signica somente que s posso enderear 9. Vamos testar isso: Exemplo: $ cat teste 53
CDTC
Brasil/DF
#!/bin/bash # Programa para testar passagem de parametros (3a. Versao) echo O programa $0 recebeu $# parametros echo "11o. parm -> $11" shift echo "2o. parm -> $1" shift 2 echo "4o. Parm -> $1" Vamos execut-lo: $ teste passando parametros para testar O programa teste recebeu 4 parametros que so: 11o. parm -> passando1 2o. parm -> parametros 4o. parm -> testar Duas coisas muito interessantes neste script: 1. Para mostrar que os nomes dos parmetros variam de $1 a $9 eu z um echo $11 e o que aconteceu? O Shell interpretou como sendo $1 seguido do algarismo 1 e listou passando1; 2. O comando shift cuja sintaxe shift n, podendo o n assumir qualquer valor numrico (porm seu default 1 como no exemplo dado), despreza os n primeiros parmetros, tornando o parmetro de ordem n+1 o primeiro, ou seja, o $1. Agora que voc j sabe mais sobre passagem de parmetros do que eu, vamos voltar nossa "cdteca"para fazer o script de incluso de CDs no meu banco chamado musicas. O programa muito simples (como tudo em Shell) e vou list-lo para voc ver: Exemplos $ cat musinc #!/bin/bash # Cadastra CDs (versao 1) # echo $1 musicas O script fcil e funcional, limito-me a anexar ao m do arquivo musicas o parmetro recebido. Vamos cadastrar 3 lbuns para ver se funciona (para no car "enchendo lingia", vou supor que em cada CD s existem 2 msicas): $ musinc "album 3^Artista5~Musica5:Artista6~Musica5" $ musinc "album 1^Artista1~Musica1:Artista2~Musica2" $ musinc "album 2^Artista3~Musica3:Artista4~Musica4" Listando o contedo de musicas. $ cat musicas album 3^Artista5~Musica5:Artista6~Musica5 album 1^Artista1~Musica1:Artista2~Musica2 54
CDTC
Brasil/DF
album 2^Artista3~Musica3:Artista4~Musica4" No est funcional como achava que deveria car. Poderia ter cado melhor. Os lbuns esto fora de ordem, dicultando a pesquisa. Vamos alterar nosso script e depois test-lo novamente: $ cat musinc #!/bin/bash # Cadastra CDs (versao 2) # echo $1 musicas sort musicas -o musicas Vamos cadastrar mais um: $ musinc "album 4^Artista7~Musica7:Artista8~Musica8" Agora, vamos ver o que aconteceu com o arquivo musicas: $ cat musicas album 1^Artista1~Musica1:Artista2~Musica2 album 2^Artista3~Musica3:Artista4~Musica4" album 3^Artista5~Musica5:Artista6~Musica5 album 4^Artista7~Musica7:Artista8~Musica8 Simplesmente inseri uma linha que classica o arquivo musicas dando a sada nele mesmo (para isso serve a opo -o), aps cada lbum ser anexado. Agora est quase funcional. Mas ateno, esta no a verso nal. O programa car muito melhor e mais amigvel, em uma nova verso que desenvolveremos aps aprendermos a adquirir os dados da tela e formatar a entrada. Exemplos Listar com o comando cat no serve, vamos, ento, fazer um programa chamado muslist para listar um lbum cujo nome ser passado como parmetro: $ cat muslist #!/bin/bash # Consulta CDs (versao 1) # grep $1 musicas Vamos execut-lo, procurando pelo album 2. Como j vimos antes, para passar a cadeia album 2 necessrio proteg-la da interpretao do Shell, para que ele no a interprete como dois parmetros. Vamos fazer assim: $ muslist "lbum 2" grep: cant open 2 55
CDTC
Centro de Difuso de Tecnologia e Conhecimento album 1^Artista1~Musica1:Artista2~Musica2 album 2^Artista3~Musica3:Artista4~Musica4" album 3^Artista5~Musica5:Artista6~Musica5 album 4^Artista7~Musica7:Artista8~Musica8
Brasil/DF
Onde est o erro? Eu tive o cuidado de colocar o parmetro passado entre aspas para o Shell no dividi-lo em dois. , mas repare como est o grep executado: grep $1 musicas Mesmo colocando lbum 2 entre aspas, para que fosse encarado como um nico parmetro, quando o $1 foi passado pelo Shell para o comando grep, transformou-se em dois argumentos. Desta forma o contedo nal da linha, que o comando grep executou foi o seguinte: grep album 2 musicas Como a sintaxe do grep : =grep [arq1, arq2, ..., arqn]= o grep entendeu que deveria procurar a cadeia de caracteres album nos arquivos 2 e musicas, Por no existir o arquivo 2 gerou o erro, e por encontrar a palavra album em todos os registros de musicas, listou a todos. Ateno: Sempre que a cadeia de caracteres a ser passada para o comando grep possuir brancos ou TAB, mesmo que dentro de variveis, coloque-a sempre entre aspas para evitar que as palavras aps o primeiro espao em branco ou TAB sejam interpretadas como nomes de arquivos. Por outro lado, melhor ignorarmos maisculas e minsculas na pesquisa. Resolveramos os dois problemas se o programa tivesse a seguinte forma: $ cat muslist #!/bin/bash # Consulta CDs (versao 2) # grep -i "$1"musicas $ muslist "album 2" album2^Artista3~Musica3:Artista4~Musica4 Neste caso, usamos a opo -i do grep que, como j vimos, serve para ignorar maisculas e minsculas e colocamos o $1 entre aspas, para que o grep continuasse a ver a cadeia de caracteres resultante da expanso da linha pelo Shell como um nico argumento de pesquisa. Agora, repare que o grep localiza a cadeia pesquisada em qualquer lugar do registro, ento da forma que estamos fazendo, podemos pesquisar por lbum, por msica, por intrprete ou at 56
CDTC
Brasil/DF
por um pedao de qualquer um destes. Quando conhecermos os comandos condicionais, montaremos uma nova verso de muslist que permitir especicar por qual campo pesquisar. Voc me diz: - Poxa, mas um saco ter que colocar o argumento de pesquisa entre aspas na hora de passar o nome do lbum. Esta forma no nem um pouco amigvel! - Tem razo, e por isso vou te mostrar uma outra forma de fazer o que voc pediu: $ cat muslist #!/bin/bash hspace*1cmtextbf# Consulta CDs (versao 2) # grep -i "$*"musicas $ muslist album 2 album2^Artista3~Musica3:Artista4~Musica4 Desta forma, o $*, que signica todos os parmetros, ser substitudo pela cadeia album 2 (de acordo com o exemplo anterior, fazendo o que voc queria. No se esquea, o problema do Shell no se voc pode ou no fazer uma determinada coisa. O problema decidir qual a melhor forma de faz-la, j que para desempenhar qualquer tarefa, a quantidade de opes enorme. Ah! Em um dia de vero voc foi praia, esqueceu o CD no carro, aquele "solzinho"de 40 graus empenou o seu CD e agora voc precisa de uma ferramenta para remov-lo do banco de dados? No tem problema, vamos desenvolver um script chamado musexc, para excluir estes CDs. Antes de desenvolver o "bacalho", quero te apresentar a uma opo bastante til da famlia de comandos grep. a opo -v, que quando usada lista todos os registros da entrada, exceto o(s) localizado(s) pelo comando. Vejamos: Exemplos $ grep -v "album 2"musicas album1^Artista1~Musica1:Artista2~Musica2 album3^Artista5~Musica5:Artista6~Musica6 album4^Artista7~Musica7:Artista8~Musica8 Conforme eu expliquei antes, o grep do exemplo listou todos os registros de msicas exceto o referente a album 2, porque atendia ao argumento do comando. Estamos, ento, prontos para desenvolver o script para remover aquele CD empenado da sua "CDteca". Ele tem a seguinte cara: $ cat musexc #!/bin/bash 57
CDTC
Brasil/DF
# Exclui CDs (versao 1) # grep -v "$1"musicas > /tmp/mus$ $ (dois cifres juntos) mv -f /tmp/mus$ $ musicas (dois cifres juntos) Na primeira linha mandei para /tpm/mus$ $ (dois cifres juntos) o arquivo musicas, sem os registros que atendessem a consulta feita pelo comando grep. Em seguida, movi (que, no duro, equivale a renomear) /tmp/mus$ $ (dois cifres juntos) por cima do antigo musicas. Usei o arquivo /tmp/mus$ $ (dois cifres juntos) como arquivo de trabalho, porque como j havia citado no artigo anterior, os dois cifres juntos contm o PID (Process Identication ou identicao do processo) e desta forma cada um que editar o arquivo musicas o far em um arquivo de trabalho diferente, desta forma evitando colises no uso. - A cara, estes programas que zemos at aqui esto muito primrios em virtude da falta de ferramentas que ainda temos. Mas bom, enquanto eu tomo mais um chope, voc vai para casa praticar em cima dos exemplos dados porque, eu prometo, chegaremos a desenvolver um sistema bacana para controle dos seus CDs. - Quando nos encontrarmos da prxima vez, vou te ensinar como funcionam os comandos condicionais e aprimoraremos mais um pouco estes scripts. - Por hoje chega! J falei demais e preciso molhar a palavra porque estou de goela seca! - Garom! Mais um sem colarinho!
58
Captulo 7
Parte III
7.1 Trabalhando com cadeias
Pelo ttulo acima no pense voc que vou lhe ensinar a ser carcereiro! Estou me referindo cadeia de caracteres!
CDTC
Brasil/DF
09876 12345 98765 $ cut -c-6 numeros 123456 098765 123455 987655 $ cut -c4- numeros 4567890 7654321 4554321 6556789 $ cut -c1,3,5,7,9 numeros 13579 08642 13542 97568 $ cut -c -3,5,8- numeros 1235890 0986321 1235321 9875789 Como d para ver, no duro mesmo existem quatro sintaxes distintas: na primeira (-c 1-5), eu especiquei uma faixa, na segunda (-c -6), especiquei tudo at uma posio, na terceira (-c 4-) de uma determinada posio em diante e na quarta (-c 1,3,5,7,9), determinadas posies. A ltima (-c -3,5,-8) virando os olhos foi s para mostrar que podemos misturar tudo.
CDTC
Brasil/DF
nome do album^interprete1 nome da musica1:...:interpreten nome da musican isto , o nome do lbum ser separado por um circunexo (^) do resto do registro, que formado por diversos grupos compostos pelo intrprete de cada msica do CD e a respectiva msica interpretada. Estes grupos so separados entre si por dois-pontos (:) e internamente, o nome do intrprete ser separado por um til (~) do nome da msica. Ento, para pegarmos os dados referentes a todas as segundas msicas do arquivo musicas, devemos fazer: $ cut -f2 -d: musicas Artista2~Musica2 Artista3~Musica4 Artista6~Musica6 Artista8~Musica8 Ou seja, cortamos o segundo campo (-f de eld em ingls) delimitado (-d) por dois-pontos (:). Mas, se quisermos somente os intrpretes, devemos fazer: $ cut -f2 -d: musicas |cut -f1 -d~ Artista2 Artista4 Artista6 Artista8 Para entender isso, vamos pegar a primeira linha de msicas: $ head -1 musica album 1^Artista1~Musica1:Artista2~Musica2 Ento, observe o que foi feito: Delimitador do primeiro cut (:) album 1^Artista1~Musica1:Artista2~Musica2 Desta forma, no primeiro cut, o primeiro campo do delimitador (-d) dois-pontos (:) album 1^Artista1~Musica1 e o segundo, que o que nos interessa, Artista2~Musica2. Vamos, ento, ver o que aconteceu no segundo cut: Novo delimitador (~) Artista2~Musica2 Agora, primeiro campo do delimitador (-d) til (~) que o que nos interessa, Artista2 e o segundo Musica2. Se o raciocnio que zemos para a primeira linha for aplicado no restante do arquivo, chegaremos 61
CDTC
Brasil/DF
7.3 O comando tr
Outro comando muito interessante o tr que serve para substituir, comprimir ou remover caracteres. Sua sintaxe segue o seguinte padro: tr [opes] cadeia1 [cadeia2] O comando tr copia o texto da entrada padro (stdin), troca as ocorrncia dos caracteres de cadeia1 pelo seu correspondente na cadeia2 ou troca mltiplas ocorrncias dos caracteres de cadeia1 por somente um caractere, ou ainda caracteres da cadeia1. As principais opes do comando so:
CDTC
Brasil/DF
nesse caso como eu traduziria? Seqncias de escape? Meio sem sentido, n? Mas v l...) que tambm so reconhecidas por outros comandos e tambm na linguagem C, e cujo signicado voc ver a seguir:
CDTC
Brasil/DF
CDTC
Brasil/DF
ftp mal feito.^M$ Dicas: Dica 1 - A opo -v do cat mostra os caracteres de controle invisveis, com a notao ^L, onde ^ a tecla control e L a respectiva letra. A opo -e$). mostra o nal da linha como um cifro. Dica 2 - Isto ocorre porque no formato DOS (ou rwin), o m dos registros formado por um Carriage-Return (\r) e um line-feed (\f). No Linux, porm, o nal do registro tem somente o line-feed. Vamos limpar este arquivo. $ tr -d \r < ArqDoDOS.txt > /tmp/ArqDoLinux.txt $ mv -f /tmp/ArqDoLinux.txt ArqDoDOS.txt Agora, vamos ver o que aconteceu: $ cat -ve ArqDoDOS.txt Este arquivo^M$ foi gerado pelo^M$ DOS/Rwin e foi^M$ baixado por um^M$ ftp mal feito.^M$ A opo -d do tr remove o caractere especicado de todo o arquivo. Desta forma eu removi os caracteres indesejados salvando em um arquivo de trabalho e posteriormente renomeei-o para a sua designao original. Obs: No Unix eu deveria fazer: $ tr -d \015 < ArqDoDOS.txt > /tmp/ArqDoLinux.txt
7.3.4 O Comando if
O que o nosso comando condicional if faz testar a varivel $?. Ento vamos ver a sua sintaxe: if cmd then cmd1 cmdn else cmd3 cmd4 cmdm
65
CDTC
Brasil/DF
ou seja, caso comando cmd tenha sido executado com sucesso, os comandos do bloco do then (cmd1, cmd2 e cmdn) sero executados, caso contrrio, os comandos executados sero os do bloco opcional do else (cmd3, cmd4 e cmdm), terminando com um . Vamos ver na prtica como isso funciona usando um scriptizinho que serve para incluir usurios no /etc/passwd: $ cat incusu #!/bin/bash # Verso 1 if grep ^$1 /etc/passwd then echo Usuario $1 j existe else if useradd $1 then echo Usurio $1 includo em /etc/passwd else echo "Problemas no cadastramento. Voc root?" Repare que o if est testando direto o comando grep e esta a sua nalidade. Caso o if$1 seja bem sucedido, ou seja, o usurio (cujo nome est em foi encontrado em /etc/passwd, os comandos do bloco do then sero executados (neste exemplo somente o echo) e, caso contrrio, as instrues do bloco do else que sero executadas, quando um novo if testa se o comando useradd foi executado a contento, criando o registro do usurio em /etc/passwd, ou no quando dar a mensagem de erro. Vejamos sua execuo, primeiramente passando um usurio j cadastrado: $ incusu jneves jneves:x:54002:1001:Julio Neves:/home/jneves:/bin/bash Usuario jneves ja existe Como j vimos diversas vezes, mas sempre bom insistir no tema para que voc j que precavido, no exemplo dado surgiu uma linha indesejada, ela a sada do comando grep. Para evitar que isso acontea, devemos desviar a sada desta instruo para /dev/null, cando assim: $ cat incusu #!/bin/bash # Verso 2 if grep ^$1 /etc/passwd > /dev/null then echo Usuario $1 j existe else if useradd $1 66
CDTC
Brasil/DF
then echo Usurio $1 includo em /etc/passwd else echo "Problemas no cadastramento. Voc root?" Agora, vamos test-lo como usurio normal (no root): $ incusu ZeNinguem ./incusu[6]: useradd: not found Problemas no cadastramento. Voc root? Epa, aquele erro no era para acontecer! Para evitar que isso acontea devemos mandar tambm a sada de erro (strerr, lembra?) do useradd para /dev/null, cando na verso nal assim: $ cat incusu #!/bin/bash # Verso 3 if grep ^$1 /etc/passwd > /dev/null then echo Usuario $1 j existe else if useradd $1 2> /dev/null then echo Usurio $1 includo em /etc/passwd else echo "Problemas no cadastramento. Voc root?" Depois destas alteraes e de fazer um su - (me tornar root) vejamos o seu comportamento: $ incusu botelho Usurio botelho incluido em /etc/passwd E novamente: $ incusu botelho Usurio botelho j existe Lembra que eu falei que ao longo dos nossos papos e chopes os nossos programas iriam se aprimorando? Ento, vejamos agora como poderamos melhorar o nosso programa para incluir msicas: $ cat musinc #!/bin/bash # Cadastra CDs (versao 3) 67
CDTC
Brasil/DF
# if grep "^$1$"musicas > /dev/null then echo Este lbum j est cadastrado else echo $1 musicas sort musicas -o musicas? Como voc viu, uma pequena evoluo da verso anterior, assim, antes de incluir um registro (que pela verso anterior poderia ser duplicado), testamos se o registro comeava (^) e terminava ($) igual ao parmetro passado ($1). O uso do circunexo (^) no incio da cadeia e cifro ($) no m, so para testar se o parmetro passado (o lbum e seus dados) so exatamente iguais a algum registro anteriormente cadastrado e no somente igual a um pedao de algum dos registros. Vamos execut-lo passando um lbum j cadastrado: $ musinc "album 4^Artista7~Musica7:Artista8~Musica8" Este lbum j est cadastrado E agora um no cadastrado: $ musinc "album 5^Artista9~Musica9:Artista10~Musica10" $ cat musicas album1^Artista1~Musica1:Artista2~Musica2 album2^Artista3~Musica3:Artista4~Musica4 album3^Artista5~Musica5:Artista6~Musica6 album4^Artista7~Musica7:Artista8~Musica8 album5^Artista9~Musica9:Artista10~Musica10 - Como voc viu, o programa melhorou um pouquinho, mas ainda no est pronto. medida que eu for te ensinando a programar em shell, nossa CDteca ir cando cada vez melhor. - Entendi tudo que voc me explicou, mas ainda no sei como fazer um if para testar condies, ou seja o uso normal do comando. - Cara, para isso existe o comando test, ele que testa condies. O comando if testa o comando test. Mas isso est meio confuso e como j falei muito, estou precisando de uns chopes para molhar a palavra. Vamos parando por aqui e na prxima vez te explico direitinho o uso do test e de diversas outras sintaxes do if. - Falou! Acho bom mesmo porque eu tambm j t cando zonzo e assim tenho tempo para praticar esse monte de coisas que voc me falou hoje. - Para xar o que voc aprendeu, tente fazer um scriptizinho para informar se um determinado usurio, que ser passado como parmetro esta logado (arghh!) ou no. - A Chico, mais dois chopes por favor...
68
Captulo 8
Parte IV
8.1 Dilogo
- E a cara, tentou fazer o exerccio que te pedi para revigorar as idias? - Claro, que sim! Em programao, se voc no treinar, no aprende. Voc me pediu para fazer um scriptizinho para informar se um determinado usurio, que ser passado como parmetro est logado (arghh!) ou no. Eu z o seguinte: $ cat logado #!/bin/bash # Pesquisa se uma pessoa est logada ou no if who | grep $1 then echo $1 est logado else echo $1 no se encontra no pedao - Calma rapaz! J vi que voc chegou cheio de teso, primeiro vamos pedir os nossos chopes de praxe e depois vamos ao Shell. Chico traz dois chopes, um sem colarinho! - Agora que j molhamos os nossos bicos, vamos dar uma olhadinha na execuo do seu bacalho: $ logado jneves jneves pts/0 Oct 18 12:02 (10.2.4.144) jneves est logado Realmente funcionou. Passei o meu login como parmetro e ele disse que eu estava logado, porm ele mandou uma linha que eu no pedi. Esta linha a sada do comando who, e para evitar que isso acontea s mand-la para o buraco negro que a esta altura voc j sabe que o /dev/null. Vejamos ento como caria: $ cat logado #!/bin/bash # Pesquisa se uma pessoa est logada ou no (verso 2) if who | grep $1 > /dev/null then echo $1 est logado
69
CDTC
Brasil/DF
else echo $1 no se encontra no pedao Agora, vamos aos testes: $ logado jneves jneves est logado $ logado chico chico no se encontra no pedao Ateno: Ah, agora sim! Lembre-se desta pegadinha, a maior parte dos comandos tem uma sada padro e uma sada de erros (o grep uma das poucas excees, j que no d mensagem de erro quando no acha uma cadeia) e necessrio estarmos atentos para redirecion-las para o buraco negro quando necessrio. Bem, agora vamos mudar de assunto: na ltima vez que nos encontramos aqui no Botequim, eu estava te mostrando os comandos condicionais e, quando j estvamos de goela seca falando sobre o if, voc me perguntou como se testa condies. Vejamos, ento, o comando test.
70
CDTC
Brasil/DF
. E pensa que acabou? Engano seu! Agora que vem o que voc est mais acostumado, ou seja, as famosas comparaes com numricos. Veja a tabela:
. Ufa! Como voc viu tem muita coisa, e como eu te disse no incio, o nosso if muito mais poderoso que o dos outros. Vamos ver em uns exemplos como isso tudo funciona, primeiramente testaremos a existncia de um diretrio: Exemplos: if test -d lmb then cd lmb else mkdir lmb cd lmb No exemplo, testei se existia um diretrio lmb denido, caso negativo (else), ele seria criado. J sei, voc vai criticar a minha lgica dizendo que o script no est otimizado. Eu sei, mas queria que voc o entendesse assim, para, ento, poder usar o ponto-de-espantao (!) como um negador do test. Veja s: if test ! -d lmb then mkdir lmb cd lmb 71
CDTC
Brasil/DF
Desta forma, o diretrio lmb seria criado somente se ele ainda no existisse, e esta negativa deve-se ao ponto-de-exclamao (!) precedendo a opo -d. Ao m da execuo deste fragmento de script, o programa estaria com certeza dentro do diretrio lmb. Vamos ver dois exemplos para entender a diferena comparao entre nmeros e entre cadeias. cad1=1 cad2=01 if test $cad1 = $cad2 then echo As variveis so iguais. else echo As variveis so diferentes. Executando o fragmento de programa acima vem: As variveis so diferentes. Vamos agora alter-lo um pouco para que a comparao seja numrica: cad1=1 cad2=01 if test $cad1 -eq $cad2 then echo As variveis so iguais. else echo As variveis so diferentes. E vamos execut-lo novamente: As variveis so iguais.
72
CDTC
Brasil/DF
$ Familia=felinae $ Genero=gato $ if test $Familia = canidea -a $Genero = lobo -o $Familia = felina -a $Genero = leo > then > echo Cuidado > else > echo Pode passar a mo > Pode passar a mo Neste exemplo, caso o animal fosse da famlia candea E (-a) do gnero lobo, OU (-o) da familia felina E (-a) do gnero leo, seria dado um alerta, caso contrrio, a mensagem seria de incentivo. Dicas: Os sinais de maior (>) no incio das linhas internas ao if so os prompts de continuao (que esto denidos na varivel $PS2) e quando o Shell identica que um comando continuar na linha seguinte, automaticamente ele o coloca at que o comando seja encerrado. Vamos mudar o exemplo para ver se continua funcionando: $ Familia=felino $ Genero=gato $ if test $Familia = felino -o $Familia = canideo -a $Genero = ona -o $Genero = lobo > then > echo Cuidado > else > echo Poe passar a mo > Cuidado Obviamente a operao redundou em erro, isto foi porque a opo -a tem precedncia sobre a -o, e desta forma o que primeiro foi avaliado foi a expresso: $Familia = canideo -a $Genero = ona Que foi avaliada como falsa, retornando o seguinte: $Familia = felino -o FALSO -o $Genero = lobo Que resolvida vem: VERDADEIRO -o FALSO -o FALSO Como agora todos conectores so -o, e para que uma srie de expresses conectadas entre si por diversos OU lgicos seja verdadeira, basta que uma delas seja, a expresso nal resultou como VERDADEIRO e o then foi executado de forma errada. Para que isso volte a funcionar, faamos o seguinte: 73
CDTC
Brasil/DF
$ if test \($Familia = felino -o $Familia = canideo\) -a \($Genero = ona -o $Genero = lobo\) > then > echo Cuidado > else > echo Pode passar a mo > Pode passar a mo Desta forma, com o uso dos parnteses agrupamos as expresses com o conector -o, priorizando as suas execues e resultando: VERDADEIRO -a FALSO Para que seja VERDADEIRO o resultado, duas expresses ligadas pelo conector -a necessrio que ambas sejam verdadeiras, o que no o caso do exemplo acima. Assim o resultado nal foi FALSO sendo, ento, o else corretamente executado. Se quisermos escolher um CD que tenha faixas de 2 artistas diferentes, nos sentimos tentados a usar um if com o conector -a, mas sempre bom lembrarmos que o bash nos d muito recursos, e isso poderia ser feito de forma muito mais simples com um nico comando grep, da seguinte maneira: $ grep Artista1 musicas |grep Artista2 Da mesma forma para escolhermos CDs que tenham a participao do Artista1 e do Artista2, no necessrio montarmos um if com o conector -o. O egrep (ou grep -E, sendo este mais aconselhvel) tambm resolve isso para ns. Veja como: $ egrep (Artista1|Artista2) musicas Ou (nesse caso especco) o prprio grep puro e simples poderia nos ajudar,: $ grep Artista[12] musicas No egrep acima, foi usada uma expresso regular, onde a barra vertical (|) trabalha como um OU lgico e os parnteses so usados para limitar a amplitude deste OU. J no grep da linha seguinte, a palavra Artista deve ser seguida por um dos valores da lista formada pelos colchetes ([ ]), isto , 1 ou 2. - T legal, eu aceito o argumento, o if do Shell muito mais poderoso que os outros caretas, mas c pra ns, essa construo de if test ... muito esquisita, pouco legvel. - voc tem razo, eu tambm no gosto disso e acho que ningum gosta. Acho que foi por isso, que o Shell incorporou outra sintaxe que substitui o comando test. Exemplos
74
CDTC
Brasil/DF
Para isso vamos pegar aquele exemplo para fazer uma troca de diretrios, que era assim: if test ! -d lmb then mkdr lmb cd lmb e utilizando a nova sintaxe, vamos faz-lo assim: if [ ! -d lmb ] then mkdir lmb cd lmb Ou seja, o comando test pode ser substitudo por um par de colchetes ([ ]), separados por espaos em branco dos argumentos, o que aumentar enormemente a legibilidade, pois o comando if ir car com a sintaxe semelhante das outras linguagens e por isso este ser o modo que o comando test ser usado daqui para a frente.
. Ou seja, quando o conector E e a primeira condio verdadeira, o resultado nal pode ser VERDADEIRO ou FALSO, dependendo da segunda condio, j no conector OU, caso a primeira condio seja verdadeira, o resultado sempre ser VERDADEIRO e se a primeira for falsa, o resultado depender da segunda condio. Os desenvolvedores do interpretador esto sempre tentando otimizar ao mximo os algoritmos. Portanto, no caso do conector E, a segunda condio no ser avaliada, caso a primeira seja falsa, j que o resultado ser sempre FALSO. J com o OU, a segunda ser executada somente caso a primeira seja falsa. Aproveitando disso, foi criada uma forma abreviada de fazer testes. foi batizado o conector E de && e o OU de || e para ver como isso funciona, vamos us-los como teste no nosso velho exemplo de trocarmos de diretrio, que em sua ltima verso estava assim: if [ ! -d lmb ] 75
CDTC
Brasil/DF
then mkdir lmb cd lmb Isso tambm poderia ser escrito da seguinte maneira: [ ! -d lmb ] && mkdir lmb cd dir Ou ainda retirando a negao (!): [ -d lmb ] || mkdir lmb cd dir No primeiro caso, se o primeiro comando (o test que est representado pelos colchetes) for bem sucedido, isto , no existir o diretrio lmb, o mkdir ser efetuado porque a primeira condio era verdadeira e o conector era E. No exemplo seguinte, testamos se o diretrio lmb existia (no anterior testamos se ele no existia) e caso isso fosse verdade, o mkdir no seria executado porque o conector era OU. Outra forma: cd lmb || mkdir lmb Neste caso, se o cd fosse mal sucedido, seria criado o diretrio lmb, mas no seria feito o cd para dentro dele. Para executarmos mais de um comando desta forma, necessrio fazermos um grupamento de comandos, e isso se consegue com o uso de chaves ( ). Veja como seria o correto: cd lmb || { mkdir lmb cd lmb } Ainda no est bom, porque caso o diretrio no exista, o cd dar a mensagem de erro correspondente. Ento, devemos fazer: cd lmb 2> /dev/null || { mkdir lmb cd lmb } Como voc viu o comando if nos permitiu fazer um cd seguro de diversas maneiras. sempre bom lembrarmos que o seguro a que me referi no tocante ao fato de que ao nal da execuo voc sempre estar dentro de lmb, desde que voc tenha permisso para entrar em lmb, permisso para criar um diretrio em ../lmb, haja espao em disco, ... 76
CDTC
Brasil/DF
. $ echo $H 13 $ [[ $H == [0-9] || $H == 1[0-2] ]] || echo Hora invlida Hora invlida $H=12 $ [[ $H == [0-9] || $H == 1[0-2] ]] || echo Hora invlida $ Neste exemplo, testamos se o contedo da varivel $H estava compreendido entre zero e nove ([0-9]) ou (||) se estava entre dez e doze (1[0-2]), dando uma mensagem de erro caso no fosse. Exemplos: Para saber se uma varivel tem o tamanho de um e somente um caractere, faa: $ var=a $ [[ $var == ? ]] && echo var tem um caractere var tem um caractere $ var=aa $ [[ $var == ? ]] && echo var tem um caractere $ Como voc pode imaginar, este uso de padres para comparao aumenta muito o poderio do comando test. No incio deste papo, antes do ltimo chope, armamos que o comando if do interpretador Shell mais poderoso que o seu similar em outras linguagens. Agora que conhecemos 77
CDTC
Brasil/DF
todo o seu espectro de funes, diga-me: voc concorda ou no com esta assertiva?
78
CDTC
Brasil/DF
. Para mostrar como ca melhor, vamos repetir o exemplo anterior, s que desta vez usaremos o case e no o if ... elif ... else ... . case $opc in 1) inclusao ;; 2) exclusao ;; 3) alteracao ;; 4) exit ;; *) echo Digite uma opo entre 1 e 4 esac Como voc deve ter percebido, eu usei o asterisco como a ltima opo, isto , se o asterisco atende a qualquer coisa, ento, ele servir para qualquer coisa que no esteja no intervalo de 1 a 4. Outro ponto a ser notado que o duplo ponto-e-vrgula no necessrio antes do esac. Exemplos: Vamos agora fazer um script mais radical. Ele te dar bom dia, boa tarde ou boa noite dependendo da hora que for executado, mas primeiramente veja estes comandos: $ date Tue Nov 9 19:37:30 BRST 2004 $ date +%H 19 O comando date informa a data completa do sistema, mas ele tem diversas opes para seu mascaramento. Neste comando, a formatao comea com um sinal de mais (+) e os caracteres de formatao vm aps um sinal de percentagem (%), assim o %H signica a hora do sistema. Dito isso vamos ao exemplo: $ cat boasvindas.sh #!/bin/bash # Programa bem educado que # d bom-dia, boa-tarde ou # boa-noite conforme a hora Hora=$(date +%H) case $Hora in 0? | 1[01]) echo Bom Dia ;; 1[2-7] ) echo Boa Tarde 79
CDTC
Brasil/DF
;; esac exit Peguei pesado, n? Que nada vamos esmiuar a resoluo caso-a-caso (ou seria case-a-case?) 0? | 1[01] - Signica zero seguido de qualquer coisa (?), ou (|) um seguido de zero ou um ( [01] ) ou seja, esta linha pegou 01, 02, ... 09, 10 e 11; 1[2-7] - Signica um seguido da lista de dois a sete, ou seja, esta linha pegou 12, 13, ... 17; * - Signica tudo que no casou com nenhum dos padres anteriores. - Cara, at agora eu falei muito e bebi pouco. Agora eu vou te passar um exerccio para voc fazer em casa e me dar a resposta da prxima vez que nos encontrarmos aqui no botequim, t legal? - T, mas antes informe ao pessoal que est acompanhando este curso conosco como eles podem te encontrar para fazer crticas, contar piada, convidar para o chope, curso ou palestra ou at mesmo para falar mal dos polticos. - fcil, meu e-mail julio.neves@gmail.com, mas pare de me embromar que eu no vou esquecer de te passar o script para fazer. o seguinte: quero que voc faa um programa que receber como parmetro o nome de um arquivo e que quando executado salvar este arquivo com o nome original seguido de um til (~) e colocar este arquivo dentro do vi (o melhor editor que se tem notcia) para ser editado. Isso para ter sempre a ltima cpia boa deste arquivo caso o cara faa alteraes indevidas. Obviamente, voc far as crticas necessrias, como vericar se foi passado um parmetro, se o arquivo passado existe, ... Enm, o que te der na telha e voc achar que deve constar do script. Deu pra entender? - Hum, hum... - Chico! Traz mais um sem colarinho que o cara aqui j est dando para entender!
80
Captulo 9
Parte V
9.1 Comandos de Loop (ou lao)
Muitos problemas requerem mecanismos de repetio nos quais sequncias de instrues precisam ser repetidas por vrias vezes usando conjuntos diferentes de dados. Mais comumente, uma seo de cdigo que se repete chamada de lao porque aps a execuo da ltima instruo o programa se bifurca e retorna primeira instruo ou encerra a execuo. As instrues de loop ou lao que veremos so o for, o while e o until que veremos daqui em diante. Comearemos pelo lao for.
CDTC
Brasil/DF
cmdn done Vamos direto para os exemplos, para entender direito o funcionamento deste comando. Vamos escrever um script para listar todos os arquivos do nosso diretrio separados por dois-pontos, mas primeiro veja: $ echo * ArqDoDOS.txt1 confuso incusu logado musexc musicas musinc muslist Isto , o Shell viu o asterisco (*) expandindo-o com o nome de todos os arquivos do diretrio e o comando echo jogou-os para a tela separados por espaos em branco. Visto isso vamos ver como resolver o problema a que nos propuzemos: $ cat testefor1 #!/bin/bash # 1o. Prog didtico para entender o for for Arq in * do echo -n $Arq: # A opcao -n eh para nao saltar linha done Ento, vamos execut-lo: $ testefor1 ArqDoDOS.txt1:confuso:incusu:logado:musexc:musicas:musinc:muslist:$ Como voc viu o Shell transformou o astersco (que odeia ser chamado de asterstico) em uma lista de arquivos separados por espaos em branco. Quando o for viu aquela lista, ele disse: "Opa, lista separadas por espaos comigo mesmo!" O bloco de comandos a ser executado era somente o echo, que com a opo -n listou a varivel $Arq seguida de dois-pontos (:), sem saltar a linha. O cifro ($) do nal da linha da execuo o prompt. que permaneceu na mesma linha tambm em funo da opo -n. Outro exemplo simples (por enquanto): $ cat testefor2 #!/bin/bash # 2o. Prog didtico para entender o for for Palavra in Papo de Botequim do echo $Palavra done
E executando vem: 82
CDTC
Brasil/DF
$ testefor2 Papo de Botequim Como voc viu, este exemplo to simples como o anterior, mas serve para mostrar o comportamento bsico do for. Veja s a fora do for: ainda estamos na primeira sintaxe do comando e j estou mostrando novas formas de us-lo. L atrs eu havia falado que o for usava listas separadas por espaos em branco, mas isso uma meia verdade, era s para facilitar a compreenso. No duro, as listas no so obrigatriamente separadas por espaos, mas antes de prosseguir te mostrarei como se comporta uma varivel do sistema chamada de $IFS. Repare seu contedo: $ echo "$IFS"| od -h 0000000 0920 0a0a 0000004 Isto , mandei a varivel (protegida da interpretao do Shell pelas aspas) para um dump hexadecimal (od -h) e resultou:
. Onde, o ltimo 0a foi proveniente do <ENTER> dado ao nal do comando. Para melhorar a explicao, vamos ver isso de outra forma: $ echo ":$IFS:"| cat -vet : ^I$ :$ Preste ateno na dica a seguir para entender a construo deste comando cat: Dica: No comando cat, a opo -e representa o <ENTER> como um cifro ($) e a opo -t representa o <TAB> como um ^I. Usei os dois-pontos (:) para mostrar o incio e o m do echo. E desta forma, mais uma vez pudemos notar que os trs caracteres esto presentes naquela varivel. Agora veja voc, IFS signica Inter Field Separator ou, traduzindo, separador entre campos. Uma vez entendido isso, eu posso armar (porque vou provar) que o comando for no usa listas separadas por espaos em branco, mas sim pelo contedo da varivel $IFS, cujo valor padro (default) 83
CDTC
Brasil/DF
so esses caracteres que acabamos de ver. Para comprovarmos isso, vamos mostrar um script que recebe o nome do artista como parmetro e lista as msicas que ele executa, mas primeiramente vamos ver como est o nosso arquivo musicas: $ cat musicas album 1^Artista1~Musica1:Artista2~Musica2 album 2^Artista3~Musica3:Artista4~Musica4 album 3^Artista5~Musica5:Artista6~Musica6 album 4^Artista7~Musica7:Artista1~Musica3 album 5^Artista9~Musica9:Artista10~Musica10 Em cima deste "leiaute"foi desenvolvido o script a seguir: $ cat listartista #!/bin/bash # Dado um artista, mostra as suas musicas if [ $# -ne 1 ] then echo Voce deveria ter passado um parametro exit 1 IFS=" :" for ArtMus in $(cut -f2 -d^ musicas) do echo "$ArtMus"| grep $1 && echo $ArtMus | cut -f2 -d~ done O script, como sempre, comea testando se os parmetros foram passados corretamente, em seguida o IFS foi setado para <ENTER> e dois-pontos (:) (como demonstram as aspas em linha diferentes), porque ele que separa os blocos Artistan~Musicam. Desta forma, a varivel $ArtMus ir receber cada um destes blocos do arquivo (repare que o for j recebe os registros sem o lbum em virtude do cut na sua linha). Caso encontre o parmetro ($1) no bloco, o segundo cut listar somente o nome da msica. Vamos execut-lo: $ listartista Artista1 Artista1 Musica1 Musica1 Artista1 Musica3 Musica3 Artista10 Musica10 Musica10 Aconteceram duas coisas indesejveis: os blocos tambm foram listados e a Musica10 idem. Alm do mais, o nosso arquivo de msicas est muito simples, na vida real, tanto a msica 84
CDTC
Brasil/DF
quanto o artista tm mais de um nome. Suponha que o artista fosse uma dupla sertaneja chamada Perereca & Peteleca. Nesta caso o $1 seria Perereca e o resto seria ignorado na pesquisa. Para que isso no ocorresse, eu devia passar o nome do artista entre aspas (") ou alterar $1 por $@ (que signica todos os parmetros passados), que a melhor soluo, mas neste caso eu teria que modicar a crtica dos parmetros e o grep. A nova crtica no seria se eu passei um parmetro, mas pelo menos um parmetro e quanto ao grep, veja s o que resultaria aps a substituio do $* (que entraria no lugar do $1) pelos parmetros: echo "$ArtMus"| grep perereca & peteleca O que resultaria em erro. O correto seria: echo "$ArtMus"| grep -i "perereca & peteleca" Onde foi colocado a opo -i para que a pesquisa ignorasse maisculas e minsculas e as aspas tambm foram inseridas para que o nome do artista fosse visto como uma s cadeia monoltica. Ainda falta consertar o erro dele ter listado o Artista10. Para isso o melhor dizer ao grep^) de $ArtMus e logo aps vem um til (~). necessrio tambm que se redirecione a sada do grep para /dev/null para que os blocos no sejam mais listados. Veja, ento, a nova (e denitiva) cara do programa: que a cadeia est no incio (cuja expresso regular $ cat listartista #!/bin/bash # Dado um artista, mostra as suas musicas # versao 2 if [ $# -eq 0 ] then echo Voce deveria ter passado pelo menos um parametro exit 1 IFS=" :" for ArtMus in $(cut -f2 -d^ musicas) do echo "$ArtMus"| grep -i "^$@~" > /dev/null && echo $ArtMus | cut -f2 -d done Que executando vem: $ listartista Artista1 Musica1 Musica3
85
CDTC
Brasil/DF
86
CDTC
Brasil/DF
Como sempre vamos execut-lo para ver se funciona mesmo: $ listamusica musica3 Musica4 "Eguinha Pocot" musica3 Artista3 Artista1 Musica4 Artista4 Eguinha Pocot No encontrada A listagem cou feia porque ainda no sabemos formatar a sada, mas qualquer dia desses, quando voc souber posicionar o cursor, fazer negrito, trabalhar com cores e etc, faremos esta listagem novamente usando todas estas ferramentas. A esta altura dos acontecimentos voc deve estar se perguntando: "E aquele for tradicional das outras linguagens em que ele sai contando a partir de um nmero, com um determinado incremento at alcanar uma condio?" E eu te respondo: "Eu no te disse que o nosso for mais porreta que os outros?"Para fazer isso existem duas formas: 1 - Com a primeira sintaxe que vimos, como nos exemplos a seguir direto no prompt: $ for i in $(seq 9) > done 123456789 > do > echo -n "$i "
Neste, a varivel i assumiu os inteiros de 1 a 9 gerados pelo comando seq e a opo -necho foi usada para no saltar linha a cada nmero listado (sinto-me ecologicamente correto por no gastar um monte de papel da revista quando isso pode ser evitado). Ainda usando o for com seq: do $ for i in $(seq 3 9) > do > echo -n "$i " > done 456789 Ou ainda na forma mais completa do seq: $ for i in $(seq 0 3 9) > do > echo -n "$i " > done 0369
87
CDTC
Brasil/DF
2 - A outra forma de fazer o desejado com uma sintaxe muito semelhante ao for da linguagem C, como veremos mais adiante.
CDTC
Brasil/DF
comandos a seguir dados diretamente no prompt para mostrar o que acabo de falar: $ echo $j $ let j++ $ echo $j 1 Ou seja, a varivel $j sequer existia e no primeiro let assumiu o valor 0 (zero) para, aps o incremento, ter o valor 1. Veja s como as coisas cam simples: $ for arq in * > do > let i++ > echo "$i -> \$Arq" > done 1 -> ArqDoDOS.txt1 2 -> confuso 3 -> incusu 4 -> listamusica 5 -> listartista 6 -> logado 7 -> musexc 8 -> musicas 9 -> musinc 10 -> muslist 11 -> testefor1 12 -> testefor2 - Pois amigo, tenho certeza que voc j tomou um xarope do comando for. Por hoje chega, na prxima vez que nos encontrarmos falaremos sobre outras instrues de loop, mas eu gostaria que at l voc zesse um pequeno script para contar a quantidade de palavras de um arquivo texto, cujo nome seria recebido por parmetro. OBS: Essa contagem tem de ser feita usando o comando for para se habituar ao seu uso. No vale usar o wc -w.
89
Captulo 10
Parte VI
10.1 Um pouco mais de for e matemtica
Voltando vaca fria, na ltima vez que aqui estivemos, terminamos o nosso papo mostrando o loop de 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 "Expanso Aritmtica"(Arithmetic Expansion) que acionado por uma construo da forma $((expresso)) ou let expresso No ltimo for citado usei a expanso das duas formas, mas no poderamos seguir adiante sem saber que a expresso pode ser de uma das listadas a seguir:
90
CDTC
Brasil/DF
. - Mas voc pensa que o papo de loop (ou lao) se encerra no comando for? Enganou-se amigo, vamos a partir de agora ver mais dois.
CDTC
Brasil/DF
lizar a palavra xefe na sada do who. Desta forma, o script dormir por 30 segundos enquanto o chefe estiver logado (Argh!). Assim que ele se desconectar do servidor, o uxo do script sair do loop e que ser verdadeiro enquanto e dar a to ansiada mensagem de liberdade. Quando o executei adivinha o que aconteceu? $ logaute.sh xefe pts/0 Jan 4 08:46 (10.2.4.144) xefe pts/0 Jan 4 08:47 (10.2.4.144) ... xefe pts/0 Jan 4 08:52 (10.2.4.144) Isto a cada 30 segundos seria enviado para a tela a sada do grep, o que no seria legal j que poluiria a tela do meu micro e a mensagem esperada poderia passar desapercebida. Para evitar isso j sabemos que a sada do pipeline tem que ser redirecionada para /dev/null. $ cat logaute.sh #!/bin/bash # Espero que a Xuxa no tenha # copyright de xefe e xato sorriso while who | grep xefe > /dev/null do sleep 30 done echo O xato se mandou, no hesite, d exit e v a luta Agora, quero montar um script que receba o nome (e eventuais parmetros) de um programa que ser executado em background e que me informe do seu trmino. Mas, para voc entender este exemplo, primeiro tenho de mostar uma nova varivel do sistema. Veja estes comandos diretos no prompt: $ sleep 10& [1] 16317 $ echo $! 16317 [1]+ Done sleep 10 $ echo $! 16317 Isto , criei um processo em background para dormir por 10 segundos, somente para mostrar que a varivel $! guarda o PID (Process IDentication) do ltimo processo em background, mas repare aps a linha do done, que a varivel reteve o valor mesmo aps o trmino deste processo. Bem, sabendo isso j ca mais fcil monitorar qualquer processo em background. Veja como: $ cat monbg.sh #!/bin/bash 92
CDTC
Brasil/DF
# Executa e monitora um # processo em background $1 & # Coloca em background while ps | grep -q $! do sleep 5 done echo Fim do Processo $1 Este script bastante similar ao anterior, mas tem uns macetes a mais, veja s: ele tem que ser executado em background para no prender o prompt, mas o $!background aps o monbg.sh propriamente dito. Repare tambm a opo -q (quiet) do grep, ela serve para tranform-lo num comando mineiro, isto , para o grepwhile ps | grep $! > /dev/null, como nos exemplos que vimos at agora. ser o do programa passado como parmetro j que ele foi colocado em "trabalhar em silncio". O mesmo resultado poderia ser obtido se a linha fosse: Dica: No esquea: o Bash disponibiliza a varivel $! que possui o PID (Process IDentication) do ltimo processo executado em background. Vamos melhorar o 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 suciente 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: $ read -p "prompt de leitura"var Onde, prompt de leitura o texto que voc quer que aparea escrito na tela, e quando o operador teclar o dado, ele ir para a varivel var. Por exemplo: $ read -p "Ttulo do lbum: "Tit Bem, uma vez entendido isso, vamos especicao do nosso problema: faremos um programa que inicialmente ler o nome do lbum e em seguida fara um loop de leitura, pegando a msica e o artista. Este loop termina quando for informada uma msica vazia, isto , ao ser solicitada a digitao da msica, o operador d um simples <ENTER>. Para facilitar a vida do operador, vamos oferecer como default o mesmo nome do artista da msica anterior (j que normal que o lbum seja todo do mesmo artista) at que ele deseje alter-lo. Vamos ver como cou: $ cat musinc #!/bin/bash # Cadastra CDs (versao 4) # clear read -p "Ttulo do lbum: "Tit [ "$Tit"] || exit 1 # Fim da execuo se ttulo vazio 93
CDTC
Brasil/DF
if grep "^$Tit\^" musicas > /dev/null then echo Este lbum j est cadastrado exit 1 Reg="$Tit^" Cont=1 oArt= while true do echo Dados da trilha $Cont: read -p "Msica: "Mus [ "$Mus"] || break # Sai se vazio read -p "Artista: $oArt // "Art [ "$Art"] && oArt="$Art"# Se vazio Art anterior Reg="$Reg$oArt $Mus:"# Montando registro Cont=$((Cont + 1)) # A linha anterior tb poderia ser ((Cont++)) done echo "$Reg> musicas sort musicas -o musicas$ cat musinc #!/bin/bash # Cadastra CDs (versao 4) # clear read -p "Ttulo do lbum: "Tit [ "$Tit"] || exit 1 # Fim da execuo se ttulo vazio if grep "^$Tit\^" musicas > /dev/null then echo Este lbum j est cadastrado exit 1 Reg="$Tit^" Cont=1 oArt= while true do echo Dados da trilha $Cont: read -p "Msica: "Mus [ "$Mus"] || break # Sai se vazio read -p "Artista: $oArt // "Art [ "$Art"] && oArt="$Art"# Se vazio Art anterior Reg="$Reg$oArt $Mus:"# Montando registro Cont=$((Cont + 1)) # A linha anterior tb poderia ser ((Cont++)) done echo "$Reg> musicas sort musicas -o musicas
94
CDTC
Brasil/DF
Este exemplo, comea com a leitura do ttulo do lbum, que se no for informado, terminar a execuo do programa. Em seguida um grep procura no incio (^) de cada registro de musicas, o ttulo informado seguido do separador (^) (que est precedido de uma contrabarra (\) para proteg-lo da interpretao do Shell). Para ler os nomes dos artistas e as msicas do lbum, foi montado um loop de while simples, cujo nico destaque o fato de estar armazenando o artista da msica anterior na varivel $oArt que s ter o seu contedo alterado, quando algum dado for informado para a varivel $Art, isto , quando no 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, porm nos falta bagagem para prosseguir. Depois que aprendermos a ler, veremos esta instruo mais a fundo. Dica: Leitura de arquivo signica ler um-a-um todos os registros, o que sempre uma operao lenta. Fique atento para no usar o while quando seu uso for desnecessrio. O Shell tem ferramentas como o sed e a famlia grep que vasculham arquivos de forma otimizada sem ser necessrio o uso de comandos de loop para faz-lo registro a registro (ou at palavra a palavra).
CDTC
Brasil/DF
xou sozinho em sua sala. Imediatamente, comecei a bisbilhotar seus arquivos - porque guerra guerra - e veja s o que descobri: $cat chegada.sh #!/bin/bash until who | grep julio do sleep 30 done echo $(date "+ Em %d/%m s %H:%Mh") > relapso.log Olha que safado! O cara estava montando um log com os horrios que eu chegava, e ainda por cima chamou o arquivo que me monitorava de relapso.log! O que ser que ele quis dizer com isso? Neste script, o pipeline who | grep julio, ser bem sucedido somente quando juliowho, isto , quando eu me "logar"no servidor. At que isso acontea, o comando sleep, que forma o bloco de instrues do until, colocar o programa em espera por 30 segundos. Quando este loop encerrarse, 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: for encontrado no comando Em 20/01 s 11:23h Quando vamos cadastrar msicas, o ideal seria que pudssemos cadastrar diversos CDs, e na ltima verso que zemos do musinc, isso no ocorre, a cada CD que cadastramos o programa termina. Vejamos como melhor-lo: $ cat musinc #!/bin/bash # Cadastra CDs (versao 5) # Para= until [ "$Para"] do clear read -p "Ttulo do lbum: "Tit if [ ! "$Tit"] # Se titulo vazio... then Para=1 # Liguei ag de sada else if grep "^$Tit\^" musicas > /dev/null then echo Este lbum j est cadastrado exit 1 Reg="$Tit^" 96
CDTC
Brasil/DF
Cont=1 oArt= while [ "$Tit"] do echo Dados da trilha $Cont: read -p "Msica: "Mus [ "$Mus"] || break # Sai se vazio read -p "Artista: $oArt // "Art [ "$Art"] && oArt="$Art"# Se vazio Art anterior Reg="$Reg$oArt $Mus:"# Montando registro Cont=$((Cont + 1)) # A linha anterior tb poderia ser ((Cont++)) done echo "$Reg> musicas sort musicas -o musicas done Nesta verso, um loop maior foi adicionado antes da leitura do ttulo, que s terminar quando a varivel $Para deixar de ser vazia. Caso o ttulo do lbum no seja informado, a varivel $Para receber valor (no caso coloquei 1, mas poderia ter colocado qualquer coisa. O importante que no seja vazia) para sair deste loop, terminando desta forma o programa. No resto, o script idntico sua verso anterior.
97
CDTC
Brasil/DF
. Duvido que voc nunca tenha deletado um arquivo e logo aps se arrependeu porque no devia t-lo removido. Pois , na dcima vez que z isso, criei um script para simular uma lixeira, isto , quando mando remover um (ou vrios) arquivo(s), o programa "nge"que removeu-o, mas o que fez foi mand-lo(s) para o diretrio /tmp/LoginName_do_usuario. Chamei este programa de erreeme e no /etc/prole coloquei a seguinte linha: alias rm=erreeme O programa era assim: $ cat erreeme #/bin/bash # # Salvando Copia de Arquivo Antes de Remove-lo #
if [ $# -eq 0 ] # Tem de ter um ou mais arquivos para remover then echo "Erro -> Uso: erreeme arq [arq] ... [arq]" echo "O uso de metacaracteres permitido. Ex. erreeme arq*" exit 1
98
CDTC
Brasil/DF
MeuDir="/tmp/$LOGNAME"# Variavel do sist. Contm o nome do usurio. if [ ! -d $MeuDir ] # Se no existir o meu diretrio sob o /tmp... then mkdir $MeuDir # Vou cria-lo
if [ ! -w $MeuDir ] # Se no posso gravar no diretrio... then echo Impossivel salvar arquivos em $MeuDir. Mude permissao... exit 2
Erro=0 # Variavel para indicar o cod. de retorno do prg for Arq # For sem o "in"recebe os parametros passados do if [ ! -f $Arq ] # Se este arquivo no existir... then echo $Arq nao existe. Erro=3 continue # Volta para o comando for
DirOrig=dirname $Arq # Cmd. dirname informa nome do dir de $Arq if [ ! -w $DirOrig ] # Verica permisso de gravacaoo no diretrio then echo Sem permissao de remover no diretorio de $Arq Erro=4 continue # Volta para o comando for
if [ "$DirOrig"= "$MeuDir"] # Se estou "esvaziando a lixeira"... then echo $Arq cara sem copia de seguranca rm -i $Arq # Pergunta antes de remover [ -f $Arq ] || echo $Arq removido # Ser que o usuario removeu? continue
cd $DirOrig # Guardo no m do arquivo o seu diretorio pwd $Arq # original para usa-lo em um script de undelete mv $Arq $MeuDir # Salvo e removido echo $Arq removido 99
CDTC
Brasil/DF
done exit $Erro # Passo eventual numero do erro para o codigo de retorno Como voc pode ver, a maior parte do script formada por pequenas crticas aos parmetros informados, mas como o script pode ter recebido diversos arquivos para remover, a cada arquivo que no se encaixa dentro do especicado, h um continue, para que a sequncia volte para o loop do for de forma a receber outros arquivos. Quando voc est no Windows (com perdo da m palavra) e tenta remover aquele monte de lixo com nomes esquisitos como HD04TG.TMP, se der erro em um deles, os outros no so removidos, no ? Ento, o continue foi usado para evitar que um improprio desses ocorra, isto , mesmo que d erro na remoo 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, no ? Pois ento a vai um desao: faa-o em casa e me traga para discutirmos no nosso prximo encontro aqui no boteco. - Poxa, mas nesse eu acho que vou danar, pois no sei nem como comear... - Cara, este programa como tudo que se faz em Shell, extremamente fcil, para ser feito em, no mximo 10 linhas. No se esquea que o arquivo est salvo em /tmp/$LOGNAME e que a sua ltima linha o diretrio em que ele residia antes de ser "removido". Tambm no se esquea de criticar se foi passado o nome do arquivo a ser removido. - eu vou tentar, mas sei no... - Tenha f irmo, eu t te falando que mole! Qualquer dvida 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 prximo 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!
100
Captulo 11
Parte VII
11.1 O comando tput
O maior uso deste comando para posicionar o cursor na tela, mas tambm muito usado para apagar dados da tela, saber a quantidade de linhas e colunas para poder posicionar corretamente um campo, apagar um campo cuja crtica detectou como errado. Enm, quase toda a formatao da tela feita por este comando. Uns poucos atributos do comando tput podem eventualmente no funcionar se o modelo de terminal denido pela varivel $TERM no tiver esta facilidade incorporada. Na tabela a seguir, apresenta os principais atributos do comando e os efeitos executados sobre o terminal, mas veja bem existem muito mais do que esses, veja s:
101
CDTC
Brasil/DF
. $ tput it 8 Neste exemplo, eu recebi o tamanho inicial da <TAB> ( Initial T ab), mas me diga: para que eu quero saber isso? Se voc quiser saber tudo sobre o comando tput (e olha que coisa que no acaba mais), veja em: http://www.cs.utah.edu/dept/old/texinfo/tput/tput.html#SEC4. Vamos fazer um programa bem fcil para mostrar alguns atributos deste comando. o famoso e famigerado Al Mundo s que esta frase ser escrita no centro da tela e em vdeo reverso e aps isso, o cursor voltar para a posio em que estava antes de escrever esta to criativa frase. Veja: $ cat alo.sh #!/bin/bash # Script bobo para testar # o comando tput (versao 1)
Colunas=tput cols # Salvando quantidade colunas Linhas=tput lines # Salvando quantidade linhas Linha=$((Linhas / 2)) # Qual eh a linha do meio da tela? Coluna=$(((Colunas - 9) / 2)) # Centrando a mensagem na tela tput sc # Salvando posicao do cursor tput cup $Linha $Coluna # Posicionando para escrever tput rev # Video reverso echo Al Mundo tput sgr0 # Restaura video ao normal tput rc # Restaura cursor aa posio original
Como o programa j est todo comentado, acho que a nica explicao necessria seria para a linha em que criada a varivel Coluna e o estranho ali aquele nmero 9, mas ele o tamanho da cadeia que pretendo escrever (Al Mundo). Desta forma este programa somente conseguiria centrar cadeias de 9 caracteres, mas veja isso: $ var=Papo $ echo $#var 4 $ var="Papo de Botequim" $ echo $#var 16
Ahhh, melhorou! Ento, agora sabemos que a construo $#variavel devolve a quantidade de caracteres de varivel. Assim sendo, vamos otimizar o nosso programa para que ele escreva em vdeo reverso, no centro da tela a cadeia passada como parmetro e depois o cursor volte 102
CDTC
Brasil/DF
posio que estava antes da execuo do script. $ cat alo.sh #!/bin/bash # Script bobo para testar # o comando tput (versao 2)
Colunas=tput cols # Salvando quantidade colunas Linhas=tput lines # Salvando quantidade linhas Linha=$((Linhas / 2)) # Qual eh a linha do meio da tela? Coluna=$(((Colunas - $#1) / 2)) #Centrando a mensagem na tela tput sc # Salvando posicao do cursor tput cup $Linha $Coluna # Posicionando para escrever tput rev # Video reverso echo $1 tput sgr0 # Restaura video ao normal tput rc # Restaura cursor aa posio original
Este script igual ao anterior, s que trocamos o valor xo da verso anterior (9), por $#1, onde este 1 o $1 ou seja, esta construo devolve o tamanho do primeiro parmetro passado para o programa. Se o parmetro que eu quiser passar tiver espaos em branco, teria que coloc-lo todo entre aspas, seno o $1$1 por $*, que como sabemos o conjunto de todos os parmetros. Ento, aquela linha caria assim: seria somente o primeiro pedao. Para evitar este aborrecimento, s substituir o Coluna=$(((Colunas - $#*) / 2)) #Centrando a mensagem na tela e a linha echo $1 passaria a ser echo $*. Mas no esquea de quando executar, passar a frase que voc deseja centrar como parmetro.
CDTC
Brasil/DF
Botequim $ read var1 var2 Papo de Botequim $ echo $var1 Papo $ echo $var2 de Botequim
Como voc viu, o read recebe uma lista separada por espaos em branco e coloca cada item desta lista em uma varivel. Se a quantidade de variveis for menor que a quantidade de tens, a ltima varivel recebe o restante. Eu disse lista separada por espaos em branco? Agora que voc j conhece tudo sobre o $IFS (Inter Field Separator) que eu te apresentei quando falvamos do comando for, ser que ainda acredita nisso? Vamos testar direto no prompt: $ oIFS="$IFS" $ IFS=: $ read var1 var2 var3 Papo de Botequim $ echo $var1 Papo de Botequim $ echo $var2 $ echo $var3 $ read var1 var2 var3 Papo:de:Botequim $ echo $var1 Papo $ echo $var2 de $ echo $var3 Botequim $ IFS="$oIFS" Viu, estava furado! O read l uma lista, assim como o for, separada pelos caracteres da varivel $IFS. Ento, veja como isso pode facilitar a sua vida: $ grep julio /etc/passwd julio:x:500:544:Julio C. Neves - 7070:/home/julio:/bin/bash $ oIFS="$IFS"# Salvando IFS $ IFS=: $ grep julio /etc/passwd | read lname lixo uid gid coment home shell $ echo -e "$lname\n$uid\n$gid\n$coment\n$home\n$shell" julio 500 104
CDTC
Brasil/DF
544 Julio C. Neves - 7070 /home/julio /bin/bash $ IFS="$oIFS"# Restaurando IFS Como voc viu, a sada do grep foi redirecionada para o comando read que leu todos os campos de uma s vez. A opo -e do echo foi usada para que o \n new line fosse entendido como um salto de linha e no como um literal. Sob o Bash existem diversas opes do read que servem para facilitar a sua vida. Veja a tabela a seguir:
. E agora direto aos exemplos curtos para demonstrar estas opes. Para ler um campo "Matrcula": $ echo -n "Matricula: "; read Mat # -n nao salta linha Matricula: 12345 $ echo $Mat 12345
Ou simplicando com a opo -p: $ read -p "Matricula: "Mat Matricula: 12345 $ echo $Mat 12345
Para ler uma determinada quantidade de caracteres: $ read -n5 -p"CEP: "Num ; read -n3 -p- Compl CEP: 12345-678$ $ echo $Num 12345 $ echo $Compl 678
105
CDTC
Brasil/DF
Neste exemplo zemos dois read: um para a primeira parte do CEP e outra para o seu complemento, deste modo formatando a entrada de dados. O cifro ($) aps o ltimo algarismo teclado, porque o read no tem o new-line implcito por default como o tem o echo. Para ler que at um determinado tempo se esgote (conhecido como time out): $ read -t2 -p "Digite seu nome completo: "Nom || echo Eta moleza! Digite seu nome completo: JEta moleza! $ echo $Nom $ Obviamente isto foi uma brincadeira, pois s tinha 3 segundos para digitar o meu nome completo e s me deu tempo de teclar um J (aquele colado no Eta), mas serviu para mostrar duas coisas: 1. O comando aps o par de barras verticais (||) (o ou lgico, lembra-se?) ser executado caso a digitao no tenha sido concluda no tempo estipulado; 2. A varivel Nom permaneceu vazia. Ela ser valorada somente quando o <ENTER> for teclado. Para ler um dado sem ser exibido na tela: $ read -sp "Senha: " Senha: $ echo $REPLY segredo
Aproveitei um erro para mostrar um macete. Quando escrevi a primeira linha, esqueci de colocar o nome da varivel que iria receber a senha, e s notei quando ia listar o seu valor. Felizmente a varivel $REPLY do Bash, possui a ltima cadeia lida e me aproveitei disso para no perder a viagem. Teste voc mesmo o que acabei de fazer. Mas o exemplo que dei, era para mostrar que a opo -s impede o que est sendo teclado de ir para a tela. Como no exemplo anterior, a falta do new-line fez com que o prompt de comando ($) permanecesse na mesma linha. Bem, agora que sabemos ler na tela vejamos como se l os dados dos arquivos.
106
CDTC
Brasil/DF
1 - Redirecionando a entrada do arquivo para o bloco do while assim: while read Linha do echo $Linha done < arquivo 2 - Redirecionando a sada de um cat para o while, da seguinte maneira: cat arquivo | while read Linha do echo $Linha done Cada um dos processos tem suas vantagens e desvantagens: Vantagens do primeiro processo: mais rpido; No necessita de um subshell para assisti-lo. Desvantagem do primeiro processo: Em um bloco de instrues grande, o redirecionamento ca pouco visvel o que por vezes prejudica a vizualizao do cdigo. Vantagem do segundo processo: Como o nome do arquivo est antes do while, mais fcil a vizualizao do cdigo. Desvantagens do segundo processo: O Pipe (|) chama um subshell para interpret-lo, tornando o processo mais lento, pesado e por vezes problemtico (veja o exemplo a seguir). Para ilustrar o que foi dito, veja estes exemplos a seguir: $ cat readpipe.sh #!/bin/bash # readpipe.sh # Exemplo de read passando arquivo por pipe.
Ultimo="(vazio)" cat $0 | # Passando o arq. do script ($0) p/ while while read Linha do Ultimo="$Linha" echo -$Ultimo-" 107
CDTC
Brasil/DF
Vamos ver sua execuo: $ readpipe.sh -#!/bin/bash-# readpipe.sh-# Exemplo de read passando arquivo por pipe. -Ultimo="(vazio)-cat $0 | # Passando o arq. do script ($0) p/ while-while read Linha-do-Ultimo="$Linha-echo -$Ultimo--done-echo "Acabou, ltimo=:$Ultimo:Acabou, ltimo=vazio): Como voc viu, o script lista todas as suas prprias linhas com um sinal de menos (-) antes e outro depois de cada, e no nal exibe o contedo da varivel $Ultimo. Repare no entanto que o contedo desta varivel permanece como (vazio). - Ser que a varivel no foi atualizada? - Foi, e isso pode ser comprovado porque a linha echo -$Ultimo-"lista corretamente as linhas. - Ento, porque isso aconteceu? - Por que como eu disse, o bloco de instrues redirecionado pelo pipe (|) executado em um subshell e l as variveis so atualizadas. Quando este subshell termina, as atualizaes das variveis vo para os pncaros do inferno junto com ele. Repare que vou fazer uma pequena mudana nele, passando o arquivo por redirecionamento de entrada (<) e as coisas passaro a funcionar na mais perfeita ordem: $ cat redirread.sh #!/bin/bash # redirread.sh # Exemplo de read passando arquivo por pipe.
Ultimo="(vazio)" while read Linha do Ultimo="$Linha" echo -$Ultimo-" done < $0 # Passando o arq. do script ($0) p/ while echo "Acabou, ltimo=:$Ultimo:"
108
CDTC
Brasil/DF
E veja a sua perfeita execuo: $ redirread.sh -#!/bin/bash-# redirread.sh-# Exemplo de read passando arquivo por pipe. -Ultimo="(vazio)-while read Linha-do-Ultimo="$Linha-echo -$Ultimo--done < $0 # Passando o arq. do script ($0) p/ while-echo "Acabou, ltimo=:$Ultimo:Acabou, ltimo=:echo "Acabou, ltimo=:$Ultimo:": Bem amigos da Rede Shell, para nalizar o comando read s falta mais um pequeno e importante macete que vou mostrar utilizando um exemplo prtico. Suponha que voc queira listar na tela um arquivo e a cada dez registros esta listagem pararia para que o operador pudesse ler o contedo da tela e ela s voltasse a rolar (scroll) aps o operador digitar qualquer tecla. Para no gastar muito papel (da Linux Magazine), vou fazer esta listagem na horizontal e o meu arquivo (numeros) tem 30 registros somente com nmeros seqnciais. Veja: $ seq 30 > numeros $ cat 10porpag.sh #!/bin/bash # Prg de teste para escrever # 10 linhas e parar para ler # Verso 1 while read Num do let ContLin++ # Contando... echo -n "$Num "# -n para nao saltar linha ((ContLin % 10)) > /dev/null || read done < numeros Na tentativa de fazer um programa genrico criamos a varivel $ContLin (por que na vida real, os registros no so somente nmeros seqenciais) e parvamos para ler quando o resto da diviso por 10 fosse zero (mandando a sada para /dev/null de forma a no aparecer na tela, sujando-a). Porm, quando fui executar aconteceu o seguinte problema: $ 10porpag.sh 1 2 3 4 5 6 7 8 9 10 12 13 14 15 16 17 18 19 20 21 23 24 25 26 27 28 29 30 Repare que faltou o nmero 11 e a listagem no parou no read. O que houve foi que toda a entrada do loop estava redirecionada do arquivo numeros e desta forma, a leitura foi feita em 109
CDTC
Brasil/DF
cima deste arquivo, desta forma perdendo o 11 (e tambm o 22). Vamos mostrar ento como deveria car para funcionar: $ cat 10porpag.sh #!/bin/bash # Prg de teste para escrever # 10 linhas e parar para ler # Verso 2 while read Num do let ContLin++ # Contando... echo -n "$Num "# -n para nao saltar linha ((ContLin % 10)) > /dev/null || read < /dev/tty done < numeros Observe que agora a entrada do read foi redirecionada por /dev/tty, que nada mais seno o terminal corrente, explicitando desta forma que aquela leitura seria feita do teclado e no de nmeros. bom realar que isto no acontece somente quando usamos o redirecionamento de entrada, se houvssemos usado o redirecionamento via pipe (|), o mesmo teria ocorrido. Veja agora a sua execuo: $ 10porpag.sh 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 Isto est quase bom mas falta um pouco para car excelente. Vamos melhorar um pouco o exemplo para que voc o reproduza e teste (mas antes de testar aumente o nmero de registros de numeros ou reduza o tamanho da tela, para que haja quebra). $ cat 10porpag.sh #!/bin/bash # Prg de teste para escrever # 10 linhas e parar para ler # Verso 3 clear while read Num do ((ContLin++)) # Contando... echo "$Num" ((ContLin % (tput lines - 3))) || read -n1 -p"Tecle Algo /dev/tty # para ler qq caractere clear # limpa a tela apos leitura 110
CDTC
Brasil/DF
done < numeros A mudana substancial feita neste exemplo com relao quebra de pgina, j que ela feita a cada quantidade-de-linhas-da-tela (tput lines) menos (-) 3, isto , se a tela tem 25 linhas, listar 22 registros e parar para leitura. No comando read-n1 para ler somente um caractere sem ser, necessariamente, um <ENTER> e a opo -p para dar a mensagem. - Bem meu amigo, por hoje s porque acho que voc j est de saco cheio... - Num t no, pode continuar... - Se voc no estiver eu estou... Mas j que voc est to empolgado com o Shell, vou te deixar um exerccio de apredizagem para voc melhorar a sua CDteca que bastante simples. Reescreva o seu programa que cadastra CDs para montar toda a tela com um nico echo e depois v posicionando frente de cada campo para receber os valores que sero teclados pelo operador. No se esquea, qualquer dvida ou falta de companhia para um chope s mandar um email para julio.neves@gmail.com. Vou aproveitar tambm para mandar o meu jab: diga para os amigos que quem estiver am de fazer um curso porreta de programao em Shell (de 40 horas) que mande um e-mail para julio.neves@tecnohall.com.br para informar-se. Valeu!
111
Captulo 12
Parte VIII
12.1 Funes
- Chico! Agora traz dois chopes, sendo um sem colarinho, para me dar inspirao. Pergunta () { # A funo recebe 3 parmetros na seguinte ordem: # $1 - Mensagem a ser dada na tela # $2 - Valor a ser aceito com resposta default # $3 - O outro valor aceito # Supondo que $1=Aceita?, $2=s e $3=n, a linha a # seguir colocaria em Msg o valor "Aceita? (S/n)" local Msg="$1 (echo $2 | tr a-z A-Z/echo $3 | tr A-Z a-z)" local TamMsg=$#Msg local Col=$(((TotCols - TamMsg) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col echo "$Msg" tput cup $LinhaMesg $((Col + TamMsg + 1)) read -n1 SN [ ! $SN ] && SN=$2 # Se vazia coloca default em SN echo $SN | tr A-Z a-z # A sada de SN ser em minscula tput cup $LinhaMesg $Col; tput el # Apaga msg da tela return # Sai da funo } Como podemos ver, uma funo denida quando fazemos nome_da_funo () e todo o seu corpo est entre chaves ({}). Assim como conversamos aqui no boteco sobre passagem de parmetros, as funes os recebem da mesma forma, isto , so parmetros posicionais ($1, $2, ..., $n) e todas as regras que se aplicam passagem de parmetros para programas, tambm valem para funes, mas muito importante realar que os parmetros passados para um programa no se confundem com aqueles que este passou para suas funes. Isso signica, por exemplo, que o $1 de um script diferente do $1 de uma de suas funes Repare que as variveis $Msg, $TamMsg e $Col so de uso restrito desta rotina, e por isso
112
CDTC
Brasil/DF
foram criadas como local. A nalidade disso simplesmente para economizar memria, j que ao sair da rotina, elas sero devidamente detonadas da partio e caso no tivesse usado este artifcio, permaneceriam residentes. A linha de cdigo que cria local Msg, concatena ao texto recebido ($1) um abre parnteses, a resposta default ($2) em caixa alta, uma barra, a outra resposta ($3) em caixa baixa e naliza fechando o parnteses. Uso esta conveno para, ao mesmo tempo, mostrar as opes disponveis e realar a resposta oferecida como default. Quase ao m da rotina, a resposta recebida ($SN) passada para caixa baixa de forma que no corpo do programa no se precise fazer este teste. Veja agora como caria a funo para dar uma mensagem na tela: function MandaMsg { # A funo recebe somente um parmetro # com a mensagem que se deseja exibir, # para no obrigar ao programador passar # a msq entre aspas, usaremos $* (todos # os parmetro, lembra?) e no $1. local Msg="$*" local TamMsg=$#Msg local Col=$(((TotCols - TamMsg) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col echo "$Msg" read -n1 tput cup $LinhaMesg $Col; tput el # Apaga msg da tela return # Sai da funo } Esta uma outra forma de denir uma funo: no a chamamos como no exemplo anterior usando uma construo com a sintaxe nome_da_funo (), mas sim como function nome_da_funo. Quanto ao mais, nada difere da anterior, exceto que, como consta dos comentrios, usamos a varivel $* que como j sabemos o conjunto de todos os parmetros passados, para que o programador no precise usar aspas envolvendo a mensagem que deseja passar para a funo. Para terminar com isso, vamos ver as alteraes que o programa necessita quando usamos o conceito de funes: $ cat musinc6 #!/bin/bash # Cadastra CDs (versao 6) #
# rea de variveis globais LinhaMesg?=$((tput lines - 3)) # Linha que msgs sero dadas para operador 113
CDTC
Brasil/DF
# rea de funes Pergunta () { # A funo recebe 3 parmetros na seguinte ordem: # $1 - Mensagem a ser dada na tela # $2 - Valor a ser aceito com resposta default # $3 - O outro valor aceito # Supondo que $1=Aceita?, $2=s e $3=n, a linha # abaixo colocaria em Msg o valor "Aceita? (S/n)" local Msg="$1 (echo $2 | tr a-z A-Z/echo $3 | tr A-Z a-z)" local TamMsg?=$#Msg local Col=$(((TotCols? - TamMsg?) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col echo "$Msg" tput cup $LinhaMesg $((Col + TamMsg? + 1)) read -n1 SN [ ! $SN ] && SN=$2 # Se vazia coloca default em SN echo $SN | tr A-Z a-z # A sada de SN ser em minscula tput cup $LinhaMesg $Col; tput el # Apaga msg da tela return # Sai da funo } function MandaMsg? { # A funo recebe somente um parmetro # com a mensagem que se deseja exibir, # para no obrigar ao programador passar # a msg entre aspas, usaremos $* (todos # os parmetros, lembra?) e no $1. local Msg="$*" local TamMsg?=${#Msg} local Col=$(((TotCols? - TamMsg?) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col echo "$Msg" read -n1 tput cup $LinhaMesg $Col; tput el # Apaga msg da tela return # Sai da funo }
# O corpo do programa propriamente dito comea aqui clear echo " Inclusao de Msicas ==== == ===
114
CDTC
Brasil/DF
Intrprete:"# Tela montada com um nico echo while true do tput cup 5 38; tput el # Posiciona e limpa linha read Album [ ! "$Album"] && # Operador deu { Pergunta "Deseja Terminar"s n [ $SN = "n"] && continue # Agora s testo a caixa baixa clear; exit # Fim da execuo } grep -iq "^$Album\^" musicas 2> /dev/null && { MandaMsg? Este lbum j est cadastrado continue # Volta para ler outro lbum } Reg="$Album^" # $Reg receber os dados de gravao oArtista= # Guardar artista anterior while true do ((Faixa++)) tput cup 7 38 echo $Faixa tput cup 9 38 # Posiciona para ler musica read Musica [ "$Musica"] || # Se o operador tiver dado ... { Pergunta "Fim de lbum?"s n [ "$SN"= n ] && continue # Agora s testo a caixa baixa break # Sai do loop para gravar dados } 115
CDTC
Brasil/DF
tput cup 11 38 # Posiciona para ler Artista [ "$oArtista"]&& echo -n "($oArtista) "# Artista anterior default read Artista [ "$Artista"] && oArtista="$Artista" Reg="$Reg$oArtista $Musica:"# Montando registro tput cup 9 38; tput el # Apaga Musica da tela tput cup 11 38; tput el # Apaga Artista da tela done echo "$Reg> musicas # Grava registro no m do arquivo sort musicas -o musicas # Classica o arquivo done Repare que a estruturao do _script_est conforme o grco a seguir:
Variveis Globais Funes Corpo do Programa Esta estruturao devido ao Shell ser uma linguagem interpretada e desta forma o programa lido da esquerda para a direita e de cima para baixo e uma varivel para ser vista, simultaneamente, pelo script e suas funes deve ser declarada (ou inicializada) antes de qualquer coisa. As funes por sua vez devem ser declaradas antes do corpo do programa propriamente dito porque no ponto em que o programador mencionou seu nome, o interpretador Shell j o havia localizado e registrado que era uma funo. Algo interessante no uso de funes faz-las o mais genrico possvel de forma que elas sirvam para outras aplicaes, sem necessidade de serem reescritas. Essas duas que acabamos de ver tm uso generalizado, pois difcil um script que tenha uma entrada de dados pelo teclado que no use uma rotina do tipo da MandaMsg ou no interage com o operador por algo semelhante Pergunta. Conselho de amigo: crie um arquivo e cada funo nova que voc criar, anexe-a a este arquivo. Ao nal de um tempo voc ter uma bela biblioteca de funes que lhe poupar muito tempo de programao.
116
CDTC
Brasil/DF
Como eu disse o .bash_prole "executado"em tempo de logon e repare que no tem nenhum direito de execuo. Isso se d porque se voc o executasse como qualquer outro script careta, quando terminasse sua execuo todo o ambiente por ele gerado morreria junto com o Shell sob o qual ele foi executado (voc se lembra que todos os scripts so executados em subshells, n?). Pois . para coisas assim que existe o comando source, tambm conhecido por . (ponto). Este comando faz com que no seja criado um novo Shell (um subshell) para executar o programa que lhe passado como parmetro. Melhor um exemplo que 453 palavras. Veja este scriptizinho a seguir: $ cat script_bobo cd .. ls Ele simplesmente deveria ir para o diretrio acima do diretrio atual. Vamos executar uns comandos envolvendo o script_bobo e vamos analisar os resultados: $ pwd /home/jneves $ script_bobo jneves juliana paula silvie $ pwd /home/jneves Se eu mandei ele subir um diretrio, porque no subiu? Subiu sim! O subshellscript tanto subiu que listou os diretrios dos quatro usurios abaixo do /home, s que assim que o script acabou, o subshell foi para o beleleu e com ele todo o ambiente criado. Olha agora como a coisa muda: $ source script_bobo jneves juliana paula silvie $ pwd /home $ cd /home/jneves $ . script_bobo jneves juliana paula silvie $ pwd /home Ah! Agora sim! Sendo passado como parmetro do comando source ou .script foi executado no Shell corrente deixando neste, todo o ambiente criado. Agora damos um rewind para o incio da explicao sobre este comando. L falamos do .bash_prole, e a esta altura voc j deve saber que a sua incumbncia , logo aps o login, deixar o ambiente de trabalho preparado para o usurio, e agora entendemos que por isso mesmo que ele executado usando este artifcio.
117
CDTC
Brasil/DF
E agora voc deve estar se perguntando se s para isso que este comando serve, e eu lhe digo que sim, mas isso nos traz um monte de vantagens e uma das mais usadas tratar funes como rotinas externas. Veja uma outra forma de fazer o nosso programa para incluir CDs no arquivo musicas: $ cat musinc7 #!/bin/bash # Cadastra CDs (versao 6) #
# rea de variveis globais LinhaMesg?=$((tput lines - 3)) # Linha que msgs sero dadas para operador TotCols?=$(tput cols) # Qtd colunas da tela para enquadrar msgs
# O corpo do programa propriamente dito comea aqui clear echo " Inclusao de Msicas ==== == ===
Intrprete:"# Tela montada com um nico echo while true do tput cup 5 38; tput el # Posiciona e limpa linha read Album [ ! "$Album"] && # Operador deu { source pergunta.func "Deseja Terminar"s n [ $SN = "n"] && continue # Agora s testo a caixa baixa clear; exit # Fim da execuo 118
CDTC
Brasil/DF
} grep -iq "^$Album\^" musicas 2> /dev/null && { . mandamsg.func Este lbum j est cadastrado continue # Volta para ler outro lbum } Reg="$Album^" # $Reg receber os dados de gravao oArtista= # Guardar artista anterior while true do ((Faixa++)) tput cup 7 38 echo $Faixa tput cup 9 38 # Posiciona para ler musica read Musica [ "$Musica"] || # Se o operador tiver dado ... { . pergunta.func "Fim de lbum?"s n [ "$SN"= n ] && continue # Agora s testo a caixa baixa break # Sai do loop para gravar dados } tput cup 11 38 # Posiciona para ler Artista [ "$oArtista"]&& echo -n "($oArtista) "# Artista anterior default read Artista [ "$Artista"] && oArtista="$Artista" Reg="$Reg$oArtista $Musica:"# Montando registro tput cup 9 38; tput el # Apaga Musica da tela tput cup 11 38; tput el # Apaga Artista da tela done echo "$Reg> musicas # Grava registro no m do arquivo sort musicas -o musicas # Classica o arquivo done Agora, o programa deu uma boa encolhida e as chamadas de funo foram trocadas por arquivos externos chamados pergunta.func e mandamsg.func, que assim podem ser chamados por qualquer outro programa, desta forma reutilizando o seu cdigo. Por motivos meramente didticos as execues de pergunta.func e mandamsg.funcsource e por . (ponto) indiscriminadamente, embora prera o source por ser mais visvel desta forma dando maior legibilidade ao cdigo e facilitando sua posterior manuteno. Veja agora como caram estes dois arquivos: $ cat pergunta.func # A funo recebe 3 parmetros na seguinte ordem: # $1 - Mensagem a ser dada na tela # $2 - Valor a ser aceito com resposta default 119
CDTC
Brasil/DF
# $3 - O outro valor aceito # Supondo que $1=Aceita?, $2=s e $3=n, a linha # abaixo colocaria em Msg o valor "Aceita? (S/n)" Msg="$1 (echo $2 | tr a-z A-Z/echo $3 | tr A-Z a-z)" TamMsg=$#Msg Col=$(((TotCols - TamMsg) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col echo "$Msg" tput cup $LinhaMesg $((Col + zTamMsg + 1)) read -n1 SN [ ! $SN ] && SN=$2 # Se vazia coloca default em SN echo $SN | tr A-Z a-z # A sada de SN ser em minscula tput cup $LinhaMesg $Col; tput el # Apaga msg da tela $ cat mandamsg.func # A funo recebe somente um parmetro # com a mensagem que se deseja exibir, # para no obrigar ao programador passar # a msq entre aspas, usaremos $* (todos # os parmetro, lembra?) e no $1. Msg="$*" TamMsg=$#Msg Col=$(((TotCols - TamMsg) / 2)) # Centra msg na linha tput cup $LinhaMesg $Col echo "$Msg" read -n1 tput cup $LinhaMesg $Col; tput el # Apaga msg da tela Em ambos os arquivos, z somente duas mudanas que veremos nas observaes a seguir, porm tenho mais trs a fazer: 1. As variveis no esto sendo mais declaradas como local, porque est uma diretiva que s pode ser usada no corpo de funes e, portanto, estas variveis permanecem no ambiente do Shell, poluindo-o; 2. O comando return no est mais presente, mas poderia estar sem alterar em nada a lgica, uma vez que ele s serviria para indicar um eventual erro via um cdigo de retorno previamente estabelecido (por exemplo return 1, return 2, ...), sendo que o return e return 0 so idnticos e signicam rotina executada sem erros; 3. O comando que estamos acostumados a usar para gerar cdigo de retorno o exit, mas a sada de uma rotina externa no pode ser feita desta forma, porque por estar sendo executada no mesmo Shell que o script chamador, o exit simplesmente encerraria este Shell, terminando a execuo de todo o script; 4. De onde surgiu a varivel LinhaMesg? Ela veio do musinc7, porque ela havia sido declarada antes da chamada das rotinas (nunca esquecendo que o Shell que est interpretando o script e estas rotinas o mesmo); 5. Se voc decidir usar rotinas externas, no se avexe, abunde os comentrios (principalmente
120
CDTC
Brasil/DF
sobre a passagem dos parmetros) para facilitar a manuteno e seu uso por outros programas no futuro. - Bem, agora voc j tem mais um monte de novidades para melhorar os scriptslistartista no qual voc passava o nome de um artista como parmetro e ele devolvia as suas msicas? Ele era assim: $ cat listartista #!/bin/bash # Dado um artista, mostra as suas musicas # versao 2 if [ $# -eq 0 ] then echo Voce deveria ter passado pelo menos um parametro exit 1 IFS=" :" for ArtMus in $(cut -f2 -d^ musicas) do echo "$ArtMus"| grep -i "^$*~" > /dev/null && echo $ArtMus verb=|= cut -f2 -d done - Claro que me lembro!... - Ento para rmar os conceitos que te passei, faa ele com a tela formatada, em loop, de forma que ele s termine quando receber um <ENTER> puro no nome do artista. Ahhh! Quando a listagem atingir a antepenltima linha da tela, o programa dever dar uma parada para que o operador possa l-las, isto , suponha que a tela tenha 25 linhas. A cada 22 msicas listadas (quantidade de linhas menos 3) o programa aguardar que o operador tecle algo para ento prosseguir. Eventuais mensagens de erro devem ser passadas usando a rotina mandamsg.func que acabamos de desenvolver. - Chico, manda mais dois, o meu com pouca presso...
121
Captulo 13
Parte IX
13.1 Envenenando a escrita
- Ufa! Agora voc j sabe tudo sobre leitura, mas sobre escrita 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? , com estes comandos voc escreve 90% das coisas necessrias, porm se precisar de escrever algo formatado eles lhe daro muito trabalho. Para formatar a sada veremos agora uma instruo muito interessante - o printf - sua sintaxe a seguinte: printf formato [argumento...] Onde: formato - uma cadeia de caracteres que contm 3 tipos de objeto: 1 - caracteres simples; 2 - caracteres para especicao de formato e 3 - seqncia de escape no padro da linguagem C. Argumento - a cadeia a ser impressa sob o controle do formato. Cada um dos caracteres utilizados para especicao de formato precedido pelo caractere % e logo a seguir vem a especicao de formato de acordo com a tabela:
. As seqncias de escape padro da linguagem C so sempre precedidas por um contra-barra (\) e as reconhecidas pelo comando printf so:
122
CDTC
Brasil/DF
. No acabou por a no! Tem muito mais coisa sobre a instruo, mas como muito cheio de detalhes e, portanto, chato para explicar e, pior ainda para ler ou estudar, vamos passar direto aos exemplos com seus comentrios, que no estou aqui para encher o saco de ningum. $ printf "%c1 caracter" 1$ Errado! S listou 1 caractere e no saltou linha ao nal $ printf "%c\n1 caracter" 1 Saltou linha mas ainda no listou a cadeia inteira $ printf "%c caractere\n"1 1 caractere Esta a forma correta o %c recebeu o 1 $ a=2 $ printf "%c caracteres\n"$a 2 caracteres O %c recebeu o valor da varivel $a $ printf "%10c caracteres\n"$a 2 caracteres $ printf "%10c\n"$a caracteres 2 c Repare que nos dois ltimos exemplos, em virtude do %c, s foi listado um caractere de cada cadeia. O 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. E tome de exemplo: $ printf "%d\n"32 32 $ printf "%10d\n"32 32 Preenche com brancos esquerda e no com zeros $ printf "%04d\n"32 0032 04 aps % signica 4 dgitos com zeros esquerda $ printf "%e\n"$(echo "scale=2 ; 100/6" | bc) 1.666000e+01 O default do %e 6 decimais $ printf "%.2e\n"echo "scale=2 ; 100/6" | bc 1.67e+01 O .2 especicou duas decimais $ printf "%f\n"32.3 32.300000 O default do %f 6 decimais $ printf "%.2f\n"32.3 123
CDTC
Brasil/DF
33.330 O bc devolveu 2 decimais. o printf colocou 0 direita $ printf "%o\n"10 12 Converteu o 10 para octal $ printf "%03o\n"10octal, n? $ printf "%s\n"Peteleca Peteleca $ printf "%15s\n"Peteleca Peteleca Peteleca com 15 caracteres enchidos com brancos $ printf "%-15sNeves\n"Peteleca Peteleca Neves O menos (-) encheu direita com brancos $ printf "%.3s\n"Peteleca Pet 3 trunca as 3 primeiras $ printf "%10.3sa\n"Peteleca Peta Pet com 10 caracteres concatenado com a (aps o s) $ printf "EXEMPLO %x\n"45232 EXEMPLO b0b0 Transformou para hexa mas os zeros no combinam $ printf "EXEMPLO %X\n"45232 EXEMPLO B0B0 Assim disfarou melhor (repare o X maisculo) $ printf "%X %XL%X\n"49354 192 10 C0CA C0LA O ltimo exemplo no marketing e bastante completo, vou coment-lo passo-a-passo: 1. O primeiro %X converteu 49354 em hexadecimal resultando C0CA (leia-se "c", "zero", "c"e "a"); 2. Em seguida veio um espao em branco seguido por outro %XL. O %X192 dando como resultado C0 que com o L fez C0L; converteu o; 3. E nalmente o ltimo %X transformou o 10 em A. Conforme vocs podem notar, a instruo printf bastante completa e complexa (ainda bem que o echo resolve quase tudo). Creio que quando resolvi explicar o printf atravs de exemplos, acertei em cheio pois no saberia como enumerar tantas regrinhas sem tornar a leitura enfadonha.
CDTC
Brasil/DF
muito trabalho, principalmente em instalaes com estrutura de diretrios com bastante nveis. HISTSIZE Limita o nmero de instrues que cabem dentro do arquivo de histrico de comandos (normalmente .bash_history, mas efetivamente o que est armazenado na varivel $HISTFILE). Seu valor default 500. HOSTNAME O nome do host corrente (que tambm pode ser obtido com o comando uname -n). LANG Usada para determinar a lngua falada no pais (mais especicamente categoria do locale). LINENO O nmero da linha do script ou da funo que est sendo executada, seu uso principal para dar mensagens de erro juntamente com as variveis $0 (nome do programa) e $FUNCNAME (nome da funo em execuo) LOGNAME Armazena o nome de login do usurio. MAILCHECK Especica, em segundos, a freqncia que o Shell vericar a presena de correspondncias nos arquivos indicados pela variveis $MAILPATH ou $MAIL. O tempo padro 60 segundos. Uma vez este tempo expirado, o Shell far esta vericao antes de exibir o prximo prompt primrio (denido em $PS1). Se esta varivel estiver sem valor ou com um valor menor ou igual a zero, a vericao de novas correspondncias no sero efetuada. PATH Caminhos que sero pesquisados para tentar localizar um arquivo especicado. Como cada script um arquivo, caso use o diretrio corrente (.) na sua varivel $PATH, voc no necessitar de usar o ./scrp para que scrp seja executado. Basta fazer scrp. Este o modo que procedo aqui no Botequim. PIPESTATUS uma varivel do tipo vetor (array) que contm uma lista valores de cdigo de retorno do ltimo pipeline executado, isto , um array que abriga cada um dos $? de cada instruo do ltimo pipeline. PROMPT_COMMAND Se esta varivel receber uma instruo, toda vez que voc der um <ENTER> direto no prompt principal ($PS1), este comando ser executado. til quando se est repetindo muito uma determinada instruo. PS1 o prompt principal. No "Papo de Botequim"usamos os seus defaults: $ para usurio comum e # para root, mas muito freqente que ele esteja customizado. Uma curiosidade que existe at concurso de quem programa o $PS1 mais criativo. (clique para dar uma googlada) 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 nmero inteiro, que um randmico entre 0 e 32767. REPLY Use esta varivel para recuperar o ltimo campo lido, caso ele no tenha nenhuma varivel associada.
125
CDTC
Brasil/DF
SECONDS Esta varivel contm a quantidade de segundos que o Shell corrente est de p. Use-a somente para esnobar um usurio daquilo que chamam de sistema operacional, mas necessita de boots freqentes. TMOUT Se tiver um valor maior do que zero, este valor ser tomado como o padro de timeout do comando read. No prompt, este valor interpretado como o tempo de espera por uma ao antes de expirar a seo. Supondo que a varivel contenha 30, o Shell dar logout aps 30 segundos de prompt sem nenhuma ao. CDPATH $ 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 cd foi executado para /usr/local/bin LANG $ date Thu Apr 14 11:54:13 BRT 2005 $ LANG=pt_BR date Qui Abr 14 11:55:14 BRT 2005 Com a especicao da varivel LANG=pt_BR (portugus do Brasil), a data passou a ser informada no padro brasileiro. interessante observarmos que no foi usado ponto-e-vrgula (;) para separar a atribuio de LANG do comando date. PIPESTATUS $ 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[*] 01 Neste exemplo, mostramos que o usurio 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, e desta forma vimos que a primeira instruo (who) foi bem sucedida (cdigo de retorno 0) e a seguinte (grep), no (cdigo de retorno 1). RANDOM Para gerar randomicamente um inteiro entre 0 e 100, fazemos: $ echo $((RANDOM%101)) 126
CDTC
Brasil/DF
73 Ou seja, pegamos o resto da diviso por 101 do nmero randmico gerado, porque o resto da diviso de qualquer nmero por 101 varia entre 0 e 100. REPLY $ 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[*] 01 $ read -p "Digite S ou N: " Digite S ou N: N $ echo $REPLY N Eu sou do tempo que memria era um bem precioso que custava muito caro. Ento, para pegar um S ou um N, no costumo a alocar um espao especial e assim sendo, pego o que foi digitado na varivel \$REPLY.
127
CDTC
Brasil/DF
Se em uma pergunta o S oferecido como valor default (padro) e a sada for para a varivel $SN, aps ler o valor podemos fazer: SN=$(SN:-S} Desta forma se o operador deu um simples <ENTER> para conrmar que aceitou o valor default, aps executar esta instruo, a varivel ter o valor S, caso contrrio, ter o valor digitado. Para sabermos o tamanho de uma cadeia: $ cadeia=0123 $ echo $#cadeia 4 Para extrair de uma cadeia da posio um at o nal, fazemos: $ cadeia=abcdef $ echo $cadeia:1 bcdef Repare que a origem zero e no um. Na mesma varivel $cadeia do exemplo acima, para extrair 3 caracteres a partir da 2 posio: $ cde Repare que, novamente, a origem da contagem zero e no um. 128
CDTC
Brasil/DF
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 Neste exemplo, foi suprimido esquerda tudo que casasse com a menor ocorrncia da expresso *' ', ou seja, tudo at o primeiro espao em branco. Estes exemplos tambm poderiam ser escritos sem protegermos o espao da interpretao do Shell (mas prero proteg-lo para facilitar a legibilidade do cdigo), veja: $ 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 termos 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 (que, como j sabemos est contido na varivel $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 esquerda tudo at a ltima barra (/) do caminho (path), desta forma sobrando somente o nome do programa. O uso do percentual (%) como se olhssemos o jogo-da-velha (#) no espelho, isto , so simtricos. Ento vejamos um exemplo para provar isso:
129
CDTC
Brasil/DF
$ 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/de/no Papo no Botequim $ echo $cadeia/de / Papo Botequim Neste caso preste a ateno quando for usar metacaracteres. Eles sempre combinaro com a maior possibilidade, veja o exemplo a seguir onde a inteno era 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 o que foi trocado foi tudo at o ltimo o. Isto poderia ser resolvido de diversas maneiras, veja algumas: $ echo $cadeia/*po/Conversa Conversa de Botequim $ echo $cadeia/????/Conversa Conversa de Botequim Trocando todas as ocorrncias de uma subcadeia por outra. Quando fazemos: $ echo $cadeia//o/a Papa de Batequim Trocamos todos as letras o por a. Outro exemplo mais til para contarmos a quantidade de arquivos existentes no diretrio corrente. Observe a linha a seguir: $ ls | wc -l 30 Viu? O wc produz um monte de espaos em branco no incio. Para tir-los, podemos fazer:
130
CDTC
Brasil/DF
$ QtdArqs=$(ls | wc -l) # QtdArqs recebe a sada do comando $ echo $QtdArqs// / 30 No ltimo exemplo, como eu sabia que a sada era composta de brancos e nmeros, montei esta expresso para trocar todos os espaos por nada. Repare que aps as duas primeiras barras existe um espao em branco. Outra forma de fazer a mesma coisa seria: $ echo $QtdArqs/* / 30 Trocando uma subcadeia no incio ou no m de uma varivel. Para trocar no incio, fazemos: $ echo $Passaro quero quero $ echo "Como diz o sulista - "$Passaro/#quero/no Como diz o sulista - no quero Para trocar no nal, fazemos: $ echo "Como diz o nordestino - "$Passaro/%quero/no Como diz o nordestino - quero no - Agora j chega, o papo hoje foi muito chato porque foi muita decoreba, mas o principal voc ter entendido o que te falei e, quando precisar, consulte estes guardanapos em que rabisquei estas dicas e depois guarde-os para consultas futuras. Mas voltando vaca fria: t na hora de tomar outro e ver o jogo do mengo. Na prxima vou te dar moleza e s vou cobrar o seguinte: pegue a rotina pergunta.func, (a que na qual falamos no incio do nosso bate papo de hoje) e otimize-a para que a varivel $SN receba o valor default por expanso de parmetros, como vimos. - Chico, v se no esquece de mim e enche meu copo.
131
Captulo 14
Parte X
14.1 O comando eval
- Vou te mostrar um problema que eu duvido que voc resolva: $ var1=3 $ var2=var1 - Te dei estas duas variveis, e quero que voc me diga como eu posso, s me referindo a $var2, listar o valor de $var1 (3). - A isso mole, s fazer: echo $echo $var2 - Repare que eu coloquei o echo $var2 entre crases ('), que desta forma ter prioridade de execuo e resultar em var1, montando echo$var1 que produzir 3... - A ? Ento, execute para ver se est correto. $ echo $echo $var2 $var1 - U! Que foi que houve? O meu raciocnio parecia bastante lgico... - O seu raciocnio realmente foi lgico, o problema que voc esqueceu de uma das primeiras coisas que te falei aqui no Boteco e vou repetir. O Shell usa a seguinte ordem para resolver uma linha de comandos: Resolve os redirecionamentos; Substitui as variveis pelos seus valores; Resolve e substitui os meta caracteres; Passa a linha j toda esmiuada para execuo. Desta forma, quando chegou na fase de resoluo de variveis, que como eu disse anterior execuo, a nica varivel existente era $var2 e por isso a tua soluo produziu como sada 132
CDTC
Brasil/DF
$var1. O comando echo identicou isso como uma cadeia e no como uma varivel. Problemas deste tipo so relativamente freqentes e seriam insolveis caso no existisse a instruo eval, cuja sintaxe : eval cmd Onde cmd uma linha de comando qualquer que voc poderia inclusive executar direto no prompt do terminal. Quando voc pe o eval na frente, no entanto, o que ocorre que o Shell trata cmd como se seus dados fossem parmetros do eval e em seguida o eval executa a linha recebida, submetendo-a ao Shell, dando ento na prtica duas passadas em cmd. Desta forma se executssemos o comando que voc props colocando o eval sua frente, teramos a sada esperada, veja: $ eval echo $echo $var2 3 Este exemplo tambm poderia ter sido feito da seguinte maneira:
CDTC
Brasil/DF
Shell para ser resolvida, desta forma s nos resta executar o comando eval para dar as duas passadas necessrias. Uma vez um colega de uma excelente lista sobre Shell Script, colocou uma dvida: queria fazer um menu que numerasse e listasse todos os arquivos com extenso .sh e quando o operador escolhesse uma opo, o programa correspondente seria executado. A minha proposta foi a seguinte: $ cat fazmenu #!/bin/bash # # Lista numerando os programas com extenso .sh no # diretrio corrente e executa o escolhido pelo operador # clear; i=1 printf "%11s\t%s\n\n"Opo Programa CASE=case $opt in for arq in *.sh do printf "\t%03d\t%s\n"$i $arq CASE="$CASE "$(printf "%03d)\t %s;;"$i $arq) i=$((i+1)) done CASE="$CASE *) . erro;; esac" read -n3 -p "Informe a opo desejada: "opt echo eval "$CASE" Parece complicado porque usei muito printf para formatao da tela, mas bastante simples, vamos entend-lo: o primeiro printf foi colocado para fazer o cabealho e logo em seguida comecei a montar dinamicamente a varivel $CASE, na qual ao nal ser feito um eval para execuo do programa escolhido. Repare no entanto que dentro do loop do for existem dois printf: o primeiro serve para formatar a tela e o segundo para montar o case (se antes do comando read voc colocar uma linha echo "$CASE", ver que o comando case montado dentro da varivel est todo indentado. Frescura, n?. Na sada do for, foi adicionada uma linha varivel $CASE, para no caso de se fazer uma opo invlida, ser executada uma funo externa para dar mensagens de erro. Vamos execut-lo para ver a sada gerada: $ fazmenu.sh Opcao Programa 001 10porpag1.sh 002 10porpag2.sh 003 10porpag3.sh 134
CDTC
Brasil/DF
004 alo1.sh 005 alo2.sh 006 contpal.sh 007 fazmenu.sh 008 logaute.sh 009 monbg.sh 010 readpipe.sh 011 redirread.sh Informe a opo desejada: Neste programa seria interessante darmos uma opo de trmino, e para isso seria necessrio a incluso de uma linha aps o loop de montagem da tela e alterarmos a linha na qual fazemos a atribuio nal do valor da varivel $CASE. Vejamos como ele caria: $ cat fazmenu #!/bin/bash # # Lista numerando os programas com extenso .sh no # diretrio corrente e executa o escolhido pelo operador # clear; i=1 printf "%11s\t%s\n\n" Opo Programa CASE=case $opt in for arq in *.sh do printf "\t%03d\t%s\n" $i $arq i=$((i+1)) done printf "\t%d\t%s\n\n"999 "Fim do programa"# Linha incluida CASE="$CASE 999) exit;; # Linha alterada *) ./erro;; esac" read -n3 -p "Informe a opo desejada: "opt echo eval "$CASE"
135
CDTC
Brasil/DF
. Alm destes sinais, existe o famigerado -9 ou SIGKILL que, para o processo que o est recebendo, equivale a colocar o dedo no boto de desligar do computador o que seria altamente indesejvel j que muitos programas necessitam "limpar o meio de campo"ao seu trmino. Se o seu nal ocorrer de forma prevista, ou seja se tiver um trmino normal, muito fcil de fazer esta limpeza, porm se o seu programa tiver um m brusco muita coisa pode ocorrer: possvel, que em um determinado espao de tempo, o seu computador esteja cheio de arquivos de trabalho inteis; Seu processador poder car atolado de processos zombies e defuncts gerados por processos lhos que perderam os pais; necessrio liberar sockets abertos para no deixar os clientes congelados; Seus bancos de dados podero car corrompidos porque sistemas gerenciadores de bancos de dados necessitam de um tempo para gravar seus buffers em disco (commit). Enm, existem mil razes para no usar um kill com o sinal -9 e para monitorar ns anormais de programas.
CDTC
Brasil/DF
S1 S2 ... SN. As aspas (") ou os apstrofos (') s so necessrios caso o trap possua mais de um comando cmd associado. Cada um dos cmd podem ser tambm uma funo interna, uma externa ou outro script. Para entender o uso de aspas (") e apstrofos (') vamos recorrer a um exemplo que trata um fragmento de um script que faz um ftp para uma mquina remota ($RemoComp), na qual o usurio $Fulano, sua senha $Segredo e vai transmitir o arquivo contido em $Arq. Suponha ainda que estas quatro variveis foram recebidas em uma rotina anterior de leitura e que este script muito usado por diversas pessoas da instalao. Vejamos este trecho de cdigo: ftp -ivn $RemoComp FimFTP /tmp/$ $ 2 /tmp/$ $ user $Fulano $Segredo binary get $Arq FimFTP Repare que, tanto as sadas dos dilogos do ftp, como os erros encontrados, esto sendo redirecionados para /tmp/$ $, o que uma construo bastante normal para arquivos temporrios usados em scripts com mais de um usurio, porque $ $ a varivel que contm o nmero do processo (PID), que nico, e com este tipo de construo evita-se que dois ou mais usurios disputem a posse e os direitos sobre o arquivo. Caso este ftp seja interrompido por um kill ou um <CTRL+C>, certamente deixar lixo no disco. exatamente esta a forma como mais se usa o comando trap. Como isto trecho de um script, devemos, logo no seu incio, como um de seus primeiros comandos, fazer: trap "rm -f /tmp/$ $ ; exit"0 1 2 3 15 Desta forma, caso houvesse uma interrupo brusca (sinais 1, 2, 3 ou 15) antes do programa encerrar (no exit dentro do comando trap) ou um m normal (sinal 0), o arquivo /tmp/$ $ seria removido. Caso na linha de comandos do trap no houvesse a instruo exit, ao nal da execuo desta linha o uxo do programa retornaria ao ponto em que estava quando recebeu o sinal que originou a execuo deste trap. Este trap poderia ser subdividido, cando da seguinte forma: trap "rm -f /tmp/$ $"0 trap "exit"1 2 3 15 Assim, ao receber um dos sinais o programa terminaria e ao terminar, geraria um sinal 0 que removeria o arquivo. Caso seu m seja normal, o sinal tambm ser gerado e o rm ser executado. Note tambm que o Shell pesquisa a linha de comandos uma vez quanto o trap interpretado 137
CDTC
Brasil/DF
(e por isso que usual coloc-lo no incio do programa) e novamente quando um dos sinais listados recebido. Ento, no ltimo exemplo, o valor de $ $ ser substitudo no momento que o comando trap foi lido da primeira vez, j que as aspas (") no protegem o cifro ($) da interpretao do Shell. Se voc desejasse que a substituio fosse realizada somente quando recebesse o sinal, o comando deveria ser colocado entre apstrofos ('). Assim, na primeira interpretao do trap, o Shell no veria o cifro ($), porm os apstrofos (') seriam removidos e nalmente o Shell poderia substituir o valor da varivel. Neste caso, a linha caria da seguinte maneira: trap rm -f /tmp/$ $ ; exit 0 1 2 3 15 Suponha dois casos: voc tem dois scripts que chamaremos de script1, cuja primeira linha ser um trap e script2, sendo este ltimo colocado em execuo pelo primeiro, e por serem dois processos, tero dois PID distintos. 1 Caso: O ftp encontra-se em script1: Neste caso, o argumento do comando trap deveria vir entre aspas (") porque caso ocorresse uma interrupo (<CTRL+C> ou <CTRL+\>) no script2, a linha s seria interpretada neste momento e o PID do script2 seria diferente do encontrado em /tmp/$ $ (no esquea que $ $ a varivel que contm o PID do processo ativo). 2 Caso: O ftp acima encontra-se em script2: Neste caso, o argumento do comando trap deveria estar entre apstrofos ('), pois caso a interrupo se desse durante a execuo de script1, o arquivo no teria sido criado, caso ocorresse durante a execuo de script2, o valor de $ $ seria o PID deste processo, que coincidiria com o de /tmp/$ $. O comando trap, quando executado sem argumentos, lista os sinais que esto sendo monitorados no ambiente, bem como a linha de comando que ser executada quando tais sinais forem recebidos. Se a linha de comandos do trap for nula (vazia), isto signica que os sinais especicados devem ser ignorados quando recebidos. Por exemplo, o comando: trap "" 2 Especica que o sinal de interrupo (<CTRL+C>) deve ser ignorado. No caso citado, quando no se deseja que sua execuo seja interrompida. No ltimo exemplo note que o primeiro argumento deve ser especicado para que o sinal seja ignorado, e no equivalente a escrever o seguinte, cuja nalidade retornar o sinal 2 ao seu estado padro (default): trap 2 Se voc ignora um sinal, todos os Subshells iro ignorar este sinal. Portanto, se voc especica qual ao deve ser tomada quando receber um sinal, ento, todos os Subshells iro tambm tomar a ao quando receberem este sinal, ou seja, os sinais so automaticamente exportados. Para o sinal que temos mostrado (sinal 2), isto signica que os Subshells sero encerrados.
138
CDTC
Brasil/DF
Suponha que voc execute o comando: trap 2 e, ento, execute um Subshell, que tornar a executar outro script como um Subshell. Se for gerado um sinal de interrupo, este no ter efeito nem sobre o Shell principal nem sobre os Subshell por ele chamados, j que todos eles ignoraro o sinal. Outra forma de restaurar um sinal ao seu default fazendo: trap � sinal Em korn shell (ksh) no existe a opo -s do comando read para ler uma senha. O que costumamos fazer usar o comando stty com a opo -echo que inibe a escrita na tela at que se encontre um stty echo para restaurar esta escrita. Ento, se estivssemos usando o interpretador ksh, a leitura da senha teria que ser feita da seguinte forma: echo -n "Senha: " stty -echo read Senha stty echo O problema neste tipo de construo que caso o operador no soubesse a senha, ele provavelmente daria um <CTRL+C> ou um <CTRL+\> durante a instruo read para descontinuar o programa e, caso ele agisse desta forma, o que quer que ele escrevesse, no apareceria na tela do seu terminal. Para evitar que isso acontea, o melhor a fazer : echo -n "Senha: " trap "stty echo exit"2 3 stty -echo read Senha stty echo trap 2 3 Para terminar este assunto, abra uma console grca e escreva no prompt de comando o seguinte: $ trap "echo Mudou o tamanho da janela"28 Em seguida, pegue o mouse e arraste-o de forma a variar o tamanho da janela corrente. Surpreso? o Shell orientado a eventos Agora escreva assim: $ trap "echo j era"17 Em seguida faa: $ sleep 3 & 139
CDTC
Brasil/DF
Voc acabou de criar um subshell que ir dormir durante trs segundos em background. Ao m deste tempo, voc receber a mensagem j era, porque o sinal 17 emitido a cada vez que um subshell termina a sua execuo. Para devolver estes sinais aos seus defaults, faa: $ trap 17 28 Ou $ trap ? 17 28 Acabamos de ver mais dois sinais que no so to importantes como os que vimos anteriormente, mas vou registr-los na tabela a seguir:
. Muito legal este comando, n? Se voc descobrir algum caso bacana de uso de sinais, por favor me informe por e-mail porque muito rara a literatura sobre o assunto.
140
CDTC
Brasil/DF
cadeiadeopcoes no pode conter interrogao (?). O nome constante da linha de sintaxe acima, dene uma varivel que cada vez que o comando getopts for executado, receber a prxima opo dos parmetros posicionais e a colocar na varivel nome. getopts coloca uma interrogao (?) na varivel denida em nome se achar uma opo no denida em cadeiadeopcoes ou se no achar o argumento esperado para uma determinada opo. Como j sabemos, cada opo passada por uma linha de comandos tem um ndice numrico, assim, a primeira opo estar contida em $1, a segunda em $2, e assim por diante. Quando o getopts obtm uma opo, ele armazena o ndice do prximo parmetro a ser processado na varivel OPTIND. Quando uma opo tem um argumento associado (indicado pelo : na cadeiadeopcoes), getopts armazena o argumento na varivel OPTARG. Se uma opo no possui argumento ou o argumento esperado no foi encontrado, a varivel OPTARG ser "matada"(unset). O comando encerra sua execuo quando: Encontra um parmetro que no comea por menos (-); O parmetro especial marca o m das opes; Quando encontra um erro (por exemplo, uma opo no reconhecida). O exemplo abaixo meramente didtico, servindo para mostrar, em um pequeno fragmento de cdigo o uso pleno do comando. $ cat getoptst.sh #!/bin/sh # Execute assim: # # getoptst.sh -h -Pimpressora arq1 arq2 # # e note que as informacoes de todas as opcoes sao exibidas # # A cadeia P:h diz que a opcao -P eh uma opcao complexa # e requer um argumento, e que h eh uma opcao simples que nao requer # argumentos. while getopts P:h OPT_LETRA do echo "getopts fez a variavel OPT_LETRA igual a $OPT_LETRA" echo "OPTARG eh $OPTARG" done used_up=expr $OPTIND - 1 echo "Dispensando os primeiros $OPTIND-1 = $used_up argumentos" shift $used_up 141
CDTC
Brasil/DF
echo "O que sobrou da linha de comandos foi $*" Para entend-lo melhor, vamos execut-lo como est sugerido em seu cabealho: $ getoptst.sh -h -Pimpressora arq1 arq2 getopts fez a variavel OPT_LETRA igual a h OPTARG eh getopts fez a variavel OPT_LETRA igual a P OPTARG eh impressora Dispensando os primeiros $OPTIND-1 = 2 argumentos O que sobrou da linha de comandos foi arq1 arq2 Desta forma, sem ter muito trabalho, separei todas as opes com seus respectivos argumentos, deixando somente os parmetros que foram passados pelo operador para posterior tratamento. Repare que se tivssemos escrito a linha de comando com o argumento (impressora) separado da opo (-P), o resultado seria exatamente o mesmo, exceto pelo $OPTIND, j que neste caso ele identica um conjunto de trs opes/argumentos e no anterior somente dois. Veja s: $ getoptst.sh -h -P impressora arq1 arq2 getopts fez a variavel OPT_LETRA igual a h OPTARG eh getopts fez a variavel OPT_LETRA igual a P OPTARG eh impressora Dispensando os primeiros $OPTIND-1 = 3 argumentos O que sobrou da linha de comandos foi arq1 arq2 Repare, no exemplo a seguir, que se passarmos uma opo invlida, a varivel $OPT_LETRA receber um ponto-de-interrogao (?) e a $OPTARG ser "apagada"(unset). $ getoptst.sh -f -Pimpressora arq1 arq2 # A opo -f no valida ./getoptst.sh: illegal option f getopts fez a variavel OPT_LETRA igual a ? OPTARG eh getopts fez a variavel OPT_LETRA igual a P OPTARG eh impressora Dispensando os primeiros $OPTIND-1 = 2 argumentos O que sobrou da linha de comandos foi arq1 arq2 - Me diz uma coisa: voc no poderia ter usado um case para evitar o getopts? - Poderia sim, mas para que? Os comandos esto a para serem usados... O exemplo dado foi didtico, mas imagine um programa que aceitasse muitas opes e seus parmetros poderiam ou no estar colados s opes, suas opes tambm poderiam ou no estar coladas, ia ser um case infernal e com getopts s seguir os passos acima. - ... Vendo desta forma acho que voc tem razo. porque eu j estou meio cansado com tanta informao nova na minha cabea. Vamos tomar a saideira ou voc ainda quer explicar alguma particularidade do Shell? - Nem um nem outro, eu tambm j cansei, mas hoje no vou tomar a saideira porque estou 142
CDTC
Brasil/DF
indo dar aula na UniRIO, que a primeira universidade federal que est preparando no uso de Software Livre, seus alunos do curso de graduao em informtica. Mas antes vou te deixar um problema: quando voc varia o tamanho de uma tela, no seu centro no aparece dinamicamente em vdeo reverso a quantidade de linhas e colunas? Ento! Eu quero que voc reproduza isso usando a linguagem Shell. - Chico, traz a minha conta.
143
Captulo 15
Parte XI
15.1 Named Pipes
Um outro tipo de pipe o named pipe, que tambm chamado de FIFO. FIFO um acrnimo de First In First Out que se refere propriedade em que a ordem dos bytes entrando no pipe a mesma que a da sada. O name em named pipe , na verdade, o nome de um arquivo. Os arquivos tipo named pipes so exibidos pelo comando ls como qualquer outro, com poucas diferenas, veja: $ ls -l pipe1 prw-r-r 1 julio dipao 0 Jan 22 23:11 pipe1| O p na coluna mais esquerda indica que fo1 um named pipe. O resto dos bitspipe funcionam como um arquivo normal. Nos sistemas mais modernos uma barra vertical (|) colocado ao m do nome do arquivo, outra dica, e nos sistemas LINUX, onde a opo de cor est habilitada, o nome do arquivo escrito em vermelho por default. Nos sistemas mais antigos, os named pipes so criados pelo programa mknod, normalmente situado no diretrio /etc. Nos sistemas mais modernos, a mesma tarefa feita pelo mkfo. O programa mkfo recebe um ou mais nomes como argumento e cria pipes com estes nomes. Por exemplo, para criar um named pipe com o nome pipe1, faa: $ mkfo pipe1 Como sempre, a melhor forma de mostrar como algo funciona dando exemplos. Suponha que ns tenhamos criado o named pipe mostrado anteriormente. Vamos agora trabalhar com duas sees ou duas consoles virtuais ou uma de cada. Em uma delas faa: $ ls -l > pipe1 e em outra faa: $ cat < pipe1
144
CDTC
Brasil/DF
A sada do comando executado na primeira console foi exibida na segunda. Note que a ordem em que os comandos ocorreram no importa. Se voc prestou ateno, reparou que o primeiro comando executado parecia ter "pendurado, congelado". Isto acontece porque a outra ponta do pipe ainda no estava conectada e, ento, o sistema operacional suspendeu o primeiro processo at que o segundo "abrisse"o pipe. Para que um processo que usa pipe no que em modo de wait, necessrio que em uma ponta do pipe tenha um processo "tagarela"e na outra um "ouvinte"e no exemplo que demos o lscat era o "orelho". Uma aplicao muito til dos named pipes permitir que programas sem nenhuma relao possam se comunicar entre si, os named pipes tambm so usados para sincronizar processos, j que em um determinado ponto voc pode colocar um processo para "ouvir"ou para "falar"em um determinado named pipe e ele s sair, se outro processo "falar"ou "ouvir"aquele pipe. Voc j viu que o uso desta ferramenta timo para sincronizar processos e para fazer bloqueio em arquivos de forma a evitar perda/corrupo de informaes devido a atualizaes simultneas (concorrncia). Vejamos exemplos para ilustrar estes casos.
. Os dois processos so disparados em paralelo e no BLOCO1 do Programa1 as trs classicaes so disparadas da seguinte maneira: for Arq in BigFile1 BigFile2 BigFile3 do if sort $Arq then Manda=va 145
CDTC
Brasil/DF
else Manda=pare break done echo $Manda > pipe1 [ $Manda = pare ] && { echo Erro durante a classicao dos arquivos exit 1 } ... Assim sendo, o comando if testa cada classicao que est sendo efetuada. Caso ocorra qualquer problema, as classicaes seguintes sero abortadas, uma mensagem contendo a cadeia pare enviada pelo pipe1 e programa1 descontinuado com um m anormal. Enquanto, o Programa1 executava o seu primeiro bloco (as classicaes) o Programa2 executava o seu BLOCO1, processando as suas rotinas de abertura e menu paralelamente ao Programa1, ganhando desta forma um bom intervalo de tempo. O fragmento de cdigo do Programa2 a seguir, mostra a transio do seu BLOCO1BLOCO2: OK=cat pipe1 if [ $OK = va ] then ... Rotina de impresso ... else # Recebeu "pare"em OK exit 1 Aps a execuo de seu primeiro bloco, o Programa2 passar a "ouvir"o pipe1, cando parado at que as classicaes do Programa1 terminem, testando a seguir a mensagem passada pelo pipe1 para decidir se os arquivos esto ntegros para serem impressos, ou se o programa dever ser descontinuado. Desta forma possvel disparar programas de forma assncrona e sincronizlos quando necessrio, ganhando bastante tempo de processamento.
146
CDTC
Brasil/DF
Desta forma, se a pgina receber dois ou mais acessos concorrentes, um ou mais poder(o) ser perdido(s), basta que o segundo acesso seja feito aps a leitura da arquivo page.hits e antes da sua gravao, isto , basta que o segundo acesso seja feito aps o primeiro ter executado a primeira linha do script e antes de executar a segunda. Ento o que fazer? Para resolver o problema de concorrncia vamos utilizar um named pipe. Criamos o seguinte script que ser o daemon que receber todos os pedidos para incrementar o contador. Note que ele vai ser usado por qualquer pgina no nosso site que precise de um contador. $ cat contahits.sh #!/bin/bash PIPE="/tmp/pipe_contador"# arquivo named pipe # dir onde serao colocados os arquivos contadores de cada pagina DIR="/var/www/contador" [ -p "$PIPE"] || mkfo "$PIPE" while : do for URL in $(cat < $PIPE) do FILE="$DIR/$(echo $URL | sed s,.*/)" # OBS1: no sed acima, como precisava procurar # uma barra,usamos vrgula como separador. # OBS2: quando rodar como daemon comente a proxima linha echo "arquivo = $FILE" n="$(cat $FILE 2> /dev/null)"|| n=0 echo $((n=n+1)) > "$FILE" done done Como s este script altera os arquivos, no existe problema de concorrncia. Este script ser um daemon, isto , rodar em background. Quando uma pgina sofrer um acesso, ela escrever a sua URL no arquivo de pipe. Para testar, execute este comando: echo "teste_pagina.html /tmp/pipe_contador Para evitar erros, em cada pgina que quisermos adicionar o contador acrescentamos a seguinte linha: <!#exec cmd="echo$REQUEST_URI > /tmp/pipe_contador--> Note que a varivel $REQUEST_URI contm o nome do arquivo que o navegador (browser) requisitou. 147
CDTC
Brasil/DF
Este ltimo exemplo, fruto de uma idia que troquei com o amigo e mestre em Shell, Thobias Salazar Trevisan que escreveu o script e colocou-o em sua excelente URL. Aconselho a todos que querem aprender Shell a dar uma olhada nela (D uma olhada e inclua-a nos favoritos). Ahhh! Voc pensa que o assunto sobre named pipes est esgotado? Enganou-se. Vou mostrar um uso diferente a partir de agora.
CDTC
Brasil/DF
Este um exemplo meramente didtico, mas so tantos os comandos que produzem mais de uma linha de sada, que serve como guia para outros. Eu quero gerar uma listagem dos meus arquivos, numerando-os e ao nal dar o total de arquivos do diretrio corrente: while read arq do ((i++)) # assim nao eh necessario inicializar i echo "$i: $arq" done < <(ls) echo "No diretorio corrente (pwd) existem $i arquivos" Eu sei que existem outras formas de executar a mesma tarefa. Usando o comando while, a forma mais comum de resolver esse problema seria: ls | while read arq do ((i++)) # assim nao eh necessario inicializar i echo "$i: $arq" done echo "No diretorio corrente (pwd) existem $i arquivos" Quando executasse o script, pareceria estar tudo certo, porm no comando echodone, voc ver que o valor de $i foi perdido. Isso deve-se ao fato desta varivel estar sendo incrementada em um subshell criado pelo pipe (|) e que terminou no comando done, levando com ele todas as variveis criadas no seu interior e as alteraes feitas em todas as variveis, inclusive as criadas externamente. Somente para te mostrar que uma varivel criada fora do subshell e alterada em seu interior perde as alteraes feitas ao seu nal, execute o script a seguir: #!/bin/bash LIST= # Criada no shell principal ls | while read FILE # Inicio do subshell do LIST="$FILE $LIST"# Alterada dentro do subshell done # Fim do subshell echo :$LIST: Ao nal da execuo voc ver que aperecero apenas dois-pontos (::). Mas no incio deste exemplo eu disse que era meramente didtico porque existem formas melhores de fazer a mesma tarefa. Veja s estas duas: $ ls | ln ou ento, usando a prpria substituio de processos: $ cat -n <(ls) 149
CDTC
Brasil/DF
Um ltimo exemplo: voc deseja comparar arq1 e arq2 usando o comando comm, mas este comando necessita que os arquivos estejam classicados. Ento, a melhor forma de proceder : $ comm <(sort arq1) <(sort arq2) Esta forma evita que voc faa as seguintes operaes: $ sort arq1 > /tmp/sort1 $ sort arq2 > /tmp/sort2 $ comm /tmp/sort1 /tmp/sort2 $ rm -f /tmp/sort1 /tmp/sort2 Pessoal, o nosso Papo de Botequim chegou ao m . sade de todos ns: Tim, Tim. - Chico, fecha a minha conta porque vou mudar de botequim. No se esquea, qualquer dvida ou falta de companhia para um chope ou at para falar mal dos polticos s mandar um e-mail para julio.neves@gmail.com. Vou aproveitar tambm para mandar o meu jab: diga para os amigos que quem estiver am de fazer um curso porreta de programao em Shell que mande um e-mail para julio.neves@uniriotec.br para informar-se. Valeu!
150