<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	xmlns:georss="http://www.georss.org/georss" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" xmlns:media="http://search.yahoo.com/mrss/"
	>

<channel>
	<title>Julio Neves</title>
	<atom:link href="http://jneves.wordpress.com/feed/" rel="self" type="application/rss+xml" />
	<link>http://jneves.wordpress.com</link>
	<description>Rio de Janeiro - Shell Script Blog</description>
	<lastBuildDate>Fri, 04 Apr 2008 15:17:22 +0000</lastBuildDate>
	<language>pt-br</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.com/</generator>
<cloud domain='jneves.wordpress.com' port='80' path='/?rsscloud=notify' registerProcedure='' protocol='http-post' />
<image>
		<url>http://s2.wp.com/i/buttonw-com.png</url>
		<title>Julio Neves</title>
		<link>http://jneves.wordpress.com</link>
	</image>
	<atom:link rel="search" type="application/opensearchdescription+xml" href="http://jneves.wordpress.com/osd.xml" title="Julio Neves" />
	<atom:link rel='hub' href='http://jneves.wordpress.com/?pushpress=hub'/>
		<item>
		<title>Papo de Botequim &#8211; Parte 1</title>
		<link>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-1/</link>
		<comments>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-1/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 16:42:41 +0000</pubDate>
		<dc:creator>jneves</dc:creator>
				<category><![CDATA[Shell]]></category>
		<category><![CDATA[>>]]></category>
		<category><![CDATA[2>]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[Bourne]]></category>
		<category><![CDATA[C Shell]]></category>
		<category><![CDATA[cat]]></category>
		<category><![CDATA[cd]]></category>
		<category><![CDATA[csh]]></category>
		<category><![CDATA[ftp]]></category>
		<category><![CDATA[kernel]]></category>
		<category><![CDATA[Korn]]></category>
		<category><![CDATA[ksh]]></category>
		<category><![CDATA[labels]]></category>
		<category><![CDATA[PID]]></category>
		<category><![CDATA[rm]]></category>
		<category><![CDATA[sh]]></category>

		<guid isPermaLink="false">http://jneves.wordpress.com/?p=17</guid>
		<description><![CDATA[Este blog contém um livro completo de Shell que escrevi para 12 fascículos da Linux Magazine. Diálogo entreouvido entre um Linuxer e em empurrador de mouse: O Ambiente Linux O Ambiente Shell Uma Rapidinha nos Principais Sabores de Shell Bourne Shell (sh) Korn Shell (ksh) Boune Again Shell (bash) C Shell (csh) Explicando o funcionamento [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=17&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div class="twikiToc">Este <i>blog</i> contém um livro completo de <i>Shell</i> que escrevi para 12 fascículos da <i>Linux Magazine</i>.</p>
<div class="twikiToc"></div>
<div class="twikiToc"><a href="http://jneves.files.wordpress.com/2008/03/julio-neves.jpg" title="julio-neves.jpg"><img src="http://jneves.files.wordpress.com/2008/03/julio-neves.jpg?w=433&#038;h=326" alt="julio-neves.jpg" height="326" width="433" /></a></div>
</div>
<div class="twikiToc"></div>
<div class="twikiToc"></div>
<div class="twikiToc">
<ul>
<li><a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Di%C3%A1logo_entreouvido_entre_um_Lin"> Diálogo entreouvido entre um Linuxer e em empurrador de mouse:</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#O_Ambiente_Linux"> O Ambiente Linux</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#O_Ambiente_Shell"> O Ambiente Shell</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Uma_Rapidinha_nos_Principais_Sab"> Uma Rapidinha nos Principais Sabores de Shell</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Bourne_Shell_sh"> Bourne Shell (sh)</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Korn_Shell_ksh"> Korn Shell (ksh)</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Boune_Again_Shell_bash"> Boune Again Shell (bash)</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#C_Shell_csh"> C Shell (csh)</a></li>
</ul>
</li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Explicando_o_funcionamento_do_Sh"> Explicando o funcionamento do Shell</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Exame_da_Linha_de_Comandos"> Exame da Linha de Comandos</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Atribui%C3%A7%C3%A3o"> Atribuição</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Comando"> Comando</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Resolu%C3%A7%C3%A3o_de_Redirecionamentos"> Resolução de Redirecionamentos</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Substitui%C3%A7%C3%A3o_de_Vari%C3%A1veis"> Substituição de Variáveis</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Substitui%C3%A7%C3%A3o_de_Meta_Caracteres"> Substituição de Meta Caracteres</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Passa_Linha_de_Comando_para_o_ke"> Passa Linha de Comando para o kernel</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Decifrando_a_Pedra_da_Roseta"> Decifrando a Pedra da Roseta</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Caracteres_para_remo%C3%A7%C3%A3o_do_signi"> Caracteres para remoção do significado</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Ap%C3%B3strofo_ou_plic"> Apóstrofo ou plic (&#8216;)</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Contrabarra_ou_Barra_Invertida"> Contrabarra ou Barra Invertida ()</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Aspas"> Aspas (&#8220;)</a></li>
</ul>
</li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Caracteres_de_redirecionamento"> Caracteres de redirecionamento</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Redirecionamento_da_Sa%C3%ADda_Padr%C3%A3o"> Redirecionamento da Saída Padrão</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Redirecionamento_da_Sa%C3%ADda_de_Err"> Redirecionamento da Saída de Erro Padrão</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Redirecionamento_da_Entrada_Padr"> Redirecionamento da Entrada Padrão</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Here_Document">Here Document</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Redirecionamento_de_Comandos"> Redirecionamento de Comandos</a></li>
</ul>
</li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo001#Caracteres_de_Ambiente"> Caracteres de Ambiente</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<h2><a title="Diálogo_entreouvido_entre_um_Lin" name="Diálogo_entreouvido_entre_um_Lin"></a> Diálogo entreouvido entre um Linuxer e em empurrador de mouse:</h2>
<p>- Quem é o <i>Bash</i>?</p>
<p>- O <i>Bash</i> é o filho mais novo da família <i>Shell</i>.</p>
<p>- Pô cara! Estás a fim de me deixar maluco? Eu tinha uma dúvida e você me deixa com duas!</p>
<p>- Não, maluco você já é há muito tempo. Desde que se decidiu a usar aquele sistema operacional que você tem que dar dez <i>boots</i> por dia e não tem domínio nenhum sobre o que esta acontecendo no seu computador. Mas deixa isso prá lá, vou te explicar o que é <i>Shell</i> e os componentes de sua família e ao final da explanação você dirá: &#8220;Meu Deus do <i>Shell</i>! Porque eu não optei pelo <i>Linux</i> antes?&#8221;.</p>
<h2><a title="O_Ambiente_Linux" name="O_Ambiente_Linux"></a> O Ambiente Linux</h2>
<p>Para você entender o que é e como funciona o <i>Shell</i>, primeiro vou te mostrar como funciona o ambiente em camadas do <i>Linux</i>. Dê uma olhada no gráfico abaixo:</p>
<p><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/grafico.png" alt="Visão do shell em relação do Kernel do Linux" /> Neste gráfico dá para ver que a camada de <b><i>hardware</i></b> é a mais profunda e é formada pelos componentes físicos do seu computador. Envolvendo esta, vem a camada do <b><i>kernel</i></b> que é o cerne do <i>Linux</i>, seu núcleo, e é quem bota o <i>hardware</i> para funcionar, fazendo seu gerenciamento e controle. Os <b>programas</b> e <b>comandos</b> que envolvem o <i>kernel</i>, dele se utilizam para realizar as tarefas aplicativas para que foram desenvolvidos. Fechando tudo isso vem o <b><i>Shell</i></b> que leva este nome porque em inglês, <i>Shell</i> significa concha, carapaça, isto é, fica entre o usuário e o sistema operacional, de forma que tudo que interage com o sistema operacional, tem que passar pelo seu crivo.</p>
<h2><a title="O_Ambiente_Shell" name="O_Ambiente_Shell"></a> O Ambiente <i>Shell</i></h2>
<p>Bom já que para chegar ao núcleo do <i>Linux</i>, no seu <i>kernel</i> que é o que interessa a todo aplicativo, é necessária a filtragem do <i>Shell</i>, vamos entender como ele funciona de forma a tirar o máximo proveito das inúmeras facilidades que ele nos oferece.</p>
<p>O <i>Linux</i> por definição é um sistema <b>multiusuário</b> &#8211; não podemos nunca esquecer disto – e para permitir o acesso de determinados usuários e barrar a entrada de outros, existe um arquivo chamado <code>/etc/passwd</code> que além fornecer dados para esta função de &#8220;leão-de-chácara&#8221; do <i>Linux</i>, também provê informações para o <i>login</i> daqueles que passaram por esta primeira barreira. O último campo de seus registros informa ao sistema qual <i>Shell</i> a pessoa vai receber ao se &#8220;logar&#8221; (ARGH!!!).</p>
<div style="border:1px dashed red;min-height:121px;background-color:#ffffcc;margin:1em;padding:1em;"><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" style="float:left;padding:0 8px 0 0;" alt="Pinguim com placa de dica" align="left" /> Quando eu disse que o último campo do <code>/etc/passwd</code> informa ao sistema qual é o <i>Shell</i> que o usuário vai receber ao se &#8220;logar&#8221;, é para ser interpretado ao pé-da-letra, isto é, se neste campo do seu registro estiver <code>prog</code>, a pessoa ao acessar o sistema receberá a tela de execução do programa <code>prog</code> e ao terminar a sua execução ganhará imediatamente um logout. Imagine o quanto se pode incrementar a segurança com este simples artifício.</div>
<p>Lembra que eu te falei de <i>Shell</i>, família, irmão? Pois é, vamos começar a entender isto: o <i>Shell</i>, que se vale da imagem de uma concha envolvendo o sistema operacional propriamente dito, é o nome genérico para tratar os filhos desta idéia que, ao longo dos anos de existência do sistema operacional <i>Unix</i> foram aparecendo. Atualmente existem diversos sabores de <i>Shell</i>, dentre estes eu destaco o <b>sh</b> (Bourne Shell), o <b>ksh</b> (Korn Shell), <b>bash</b> (Bourne Again Shell) e o <b>csh</b> (C Shell).</p>
<h3><a title="Uma_Rapidinha_nos_Principais_Sab" name="Uma_Rapidinha_nos_Principais_Sab"></a> Uma Rapidinha nos Principais Sabores de <i>Shell</i></h3>
<h4><a title="Bourne_Shell_sh" name="Bourne_Shell_sh"></a><a title="Bourne_Shell_sh_" name="Bourne_Shell_sh_"></a> Bourne Shell (sh)</h4>
<p>Desenvolvido por Stephen Bourne da Bell Labs (da AT&amp;T onde também foi desenvolvido o <i>Unix</i>), este foi durante muitos anos o <i>Shell default</i> do sistema operacional <i>Unix</i>. É também chamado de <i>Standard Shell</i> por ter sido durante vários anos o único e até hoje é o mais utilizado até porque ele foi portado para todos os ambientes <i>Unix</i> e distros <i>Linux</i>.</p>
<h4><a title="Korn_Shell_ksh" name="Korn_Shell_ksh"></a><a title="Korn_Shell_ksh_" name="Korn_Shell_ksh_"></a> Korn Shell (ksh)</h4>
<p>Desenvolvido por David Korn, também da <i>Bell Labs</i>, é um superset do sh, isto é, possui todas as facilidades do sh e a elas agregou muitas outras. A compatibilidade total com o sh vem trazendo muitos usuários e programadores de <i>Shell</i> para este ambiente.</p>
<h4><a title="Boune_Again_Shell_bash" name="Boune_Again_Shell_bash"></a><a title="Boune_Again_Shell_bash_" name="Boune_Again_Shell_bash_"></a> Boune Again Shell (bash)</h4>
<p>Este é o <i>Shell</i> mais moderno e cujo número de adeptos mais cresce em todo o mundo, seja por ser o <i>Shell default</i> do <i>Linux</i>, seu sistema operacional hospedeiro, seja por sua grande diversidade de comandos, que incorpora inclusive diversos instruções características do C Shell.</p>
<h4><a title="C_Shell_csh" name="C_Shell_csh"></a><a title="C_Shell_csh_" name="C_Shell_csh_"></a> C Shell (csh)</h4>
<p>Desenvolvido por Bill Joy da Berkley University é o <i>Shell</i> mais utilizado em ambientes <i>*BSD</i> e <i>Xenix</i>. A estruturação de seus comandos é bem similar à da linguagem C. Seu grande pecado foi ignorar a compatibilidade com o sh, partindo por um caminho próprio.</p>
<p>Além destes <i>Shells</i> existem outros, mas irei falar contigo somente sobre os três primeiros, tratando-os genericamente por <i>Shell</i> e assinalando as especificidades de cada um que porventura hajam.</p>
<h3><a title="Explicando_o_funcionamento_do_Sh" name="Explicando_o_funcionamento_do_Sh"></a> Explicando o funcionamento do <i>Shell</i></h3>
<p>O <i>Shell</i> é o primeiro programa que você ganha ao se &#8220;logar&#8221; no <i>Linux</i>. É ele que vai resolver um monte de coisas de forma a não onerar o <i>kernel</i> com tarefas repetitivas, aliviando-o para tratar assuntos mais nobres. Como cada usuário possui o seu próprio <i>Shell</i> interpondo-se entre ele e o <i>Linux</i>, é o <i>Shell</i> quem interpreta os comandos que são teclados e examina as suas sintaxes, passando-os esmiuçados para execução.</p>
<p>- Êpa! Esse negócio de interpreta comando não tem nada a haver com interpretador não, né?</p>
<p>- Tem sim, na verdade o <i>Shell</i> é um interpretador (ou será intérprete) que traz consigo uma poderosa linguagem com comandos de alto nível, que permite construção de <i>loops</i> (laços), de tomadas de decisão e de armazenamento de valores em variáveis, como vou te mostrar.</p>
<p>Vou te explicar as principais tarefas que o <i>Shell</i> cumpre, na sua ordem de execução. Preste atenção nesta ordem porque ela é fundamental para o entendimento do resto do nosso bate papo.</p>
<h4><a title="Exame_da_Linha_de_Comandos" name="Exame_da_Linha_de_Comandos"></a> Exame da Linha de Comandos</h4>
<p>Neste exame o <i>Shell</i> identifica os caracteres especiais (reservados) que têm significado para interpretação da linha, logo após verifica se a linha passada é uma atribuição ou um comando.</p>
<h5><a title="Atribuição" name="Atribuição"></a> Atribuição</h5>
<p>Se o <i>Shell</i> encontra dois campos separados por um sinal de igual (<code>=</code>) <b>sem espaços em branco entre eles</b>, identifica esta seqüência como uma atribuição.</p>
<p>Exemplos</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ ls linux<br />
<font color="#ffffff">linux</font></div>
<p>Neste exemplo o <i>Shell</i> identificou o <code>ls</code> como um programa e o <i>linux</i> como um parâmetro passado para o programa <code>ls</code>.</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ valor=1000</div>
<p>Neste caso, por não haver espaços em branco (já dá para notar que o branco é um dos caracteres reservados) o <i>Shell</i> identificou uma atribuição e colocou <code>1000</code> na variável <code>valor</code>.</p>
<div style="border:1px dashed red;min-height:121px;background-color:#ffffcc;margin:1em;padding:1em;"><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" style="float:left;padding:0 8px 0 0;" alt="Pinguim com placa de dica" align="left" /> <b>Jamais Faça:</b></p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ valor = 1000<br />
<font color="#ffffff">bash: valor: not found</font></div>
<p>Neste caso, o <i>Bash</i> achou a palavra valor isolada por brancos e julgou que você estivesse mandando executar um programa chamado valor, para o qual estaria passando dois parâmetros: <code>=</code> e <code>1000</code>.</div>
<h5><a title="Comando" name="Comando"></a> Comando</h5>
<p>Quando uma linha é digitada no <i>prompt</i> do <i>Linux</i>, ela é dividida em pedaços separados por espaço em branco: o primeiro pedaço é o nome do programa que terá sua existência pesquisada; identifica em seguida, nesta ordem, opções/parâmetros, redirecionamentos e variáveis.</p>
<p>Quando o programa identificado existe, o <i>Shell</i> verifica as permissões dos arquivos envolvidos (inclusive o próprio programa), dando um erro caso você não esteja credenciado a executar esta tarefa.</p>
<h6><a title="Resolução_de_Redirecionamentos" name="Resolução_de_Redirecionamentos"></a> Resolução de Redirecionamentos</h6>
<p>Após identificar os componentes da linha que você teclou, o <i>Shell</i> parte para a resolução de redirecionamentos. O <i>Shell</i> tem incorporado ao seu elenco de vantagens o que chamamos de redirecionamento, que pode ser de entrada (<code>stdin</code>), de saída (<code>stdout</code>) ou dos erros (<code>stderr</code>), conforme vou te explicar a seguir.</p>
<h6><a title="Substituição_de_Variáveis" name="Substituição_de_Variáveis"></a> Substituição de Variáveis</h6>
<p>Neste ponto, o <i>Shell</i> verifica se as eventuais variáveis (parâmetros começados por <code>$</code>), encontradas no escopo do comando, estão definidas e as substitui por seus valores atuais.</p>
<h6><a title="Substituição_de_Meta_Caracteres" name="Substituição_de_Meta_Caracteres"></a> Substituição de Meta Caracteres</h6>
<p>Se algum metacaractere (<code>*</code>, <code>?</code> ou <code>[]</code>) foi encontrado na linha de comando, neste ponto ele será substituído por seus possíveis valores. Supondo que o único arquivo no seu diretório corrente começado pela letra <code>n</code> seja um diretório chamado <code>nomegrandeprachuchu</code>, se você fizer:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ cd n*</div>
<p>Como até aqui quem esta trabalhando a sua linha é o <i>Shell</i> e o comando (programa) <code>cd</code> ainda não foi executado, o <i>Shell</i> transforma o <code>n*</code> em <code>nomegrandeprachuchu</code> e o comando <code>cd</code> será executado com sucesso.</p>
<h6><a title="Passa_Linha_de_Comando_para_o_ke" name="Passa_Linha_de_Comando_para_o_ke"></a> Passa Linha de Comando para o kernel</h6>
<p>Completadas as tarefas anteriores, o <i>Shell</i> monta a linha de comandos, já com todas as substituições feitas, chama o <i>kernel</i> para executá-la em um novo <i>Shell</i> (<i>Shell</i> filho), ganhando um número de processo (PID ou <i><kbd>P</kbd>rocess <kbd>ID</kbd>entification</i>) e permanece inativo, tirando uma soneca, durante a execução do programa. Uma vez encerrado este processo (juntamente com o <i>Shell</i> filho), recebe novamente o controle e, exibindo um <i>prompt</i>, mostra que está pronto para executar outros comandos.</p>
<h3><a title="Decifrando_a_Pedra_da_Roseta" name="Decifrando_a_Pedra_da_Roseta"></a> Decifrando a Pedra da Roseta</h3>
<p>Para tirar aquela sensação que você tem quando vê um <i>script Shell</i>, que mais parece uma sopa de letrinhas ou um hieróglifo vou lhe mostrar os principais caracteres especiais para que você saia por ai como o <b><i>Jean-François Champollion</i></b>  decifrando a Pedra da Roseta (dê uma <a href="http://www.google.com.br/search?num=100&amp;hl=pt-BR&amp;q=%22Jean-Fran%C3%A7ois+Champollion%22&amp;btnG=Pesquisar&amp;meta=cr%3DcountryBR" target="_blank">&#8220;googlada&#8221;</a> para descobrir quem é este cara, acho que vale a pena).</p>
<h4><a title="Caracteres_para_remoção_do_signi" name="Caracteres_para_remoção_do_signi"></a> Caracteres para remoção do significado</h4>
<p>É isso mesmo, quando não desejamos que o <i>Shell</i> interprete um caractere especial, devemos &#8220;escondê-lo&#8221; dele. Isso pode ser feito de três formas distintas:</p>
<h5><a title="Apóstrofo_ou_plic" name="Apóstrofo_ou_plic"></a><a title="Apóstrofo_ou_plic_" name="Apóstrofo_ou_plic_"></a> Apóstrofo ou plic (<code>'</code>)</h5>
<p>Quando o <i>Shell</i> vê uma cadeia de caracteres entre apóstrofos (<code>'</code>), ele tira os apóstrofos da cadeia e não interpreta seu conteúdo.</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ ls linux*<br />
<font color="#ffffff">linuxmagazine</font><br />
$ ls &#8216;linux*&#8217;<br />
<font color="#ffffff">bash: linux* no such file or directory</font></div>
<p>No primeiro caso o <i>Shell</i> &#8220;expandiu&#8221; o asterisco e descobriu o arquivo <code>linuxmagazine</code> para listar. No segundo, os apóstrofos inibiram a interpretação do <i>Shell</i> e veio a resposta que não existe o arquivo <code>linux*</code>.</p>
<h5><a title="Contrabarra_ou_Barra_Invertida" name="Contrabarra_ou_Barra_Invertida"></a><a title="Contrabarra_ou_Barra_Invertida_" name="Contrabarra_ou_Barra_Invertida_"></a> Contrabarra ou Barra Invertida ()</h5>
<p>Idêntico aos apóstrofos exceto que a barra invertida inibe a interpretação somente do caractere que a segue.</p>
<p>Suponha que você acidentalmente tenha criado um arquivo chamado <code>*</code> (asterisco) – que alguns sabores de <i>Unix</i> permitem &#8211; e deseja removê-lo. Se você fizesse:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ rm *</div>
<p>Você estaria fazendo a maior encrenca, pois o <code>rm</code> removeria todos os arquivos do diretório corrente. A melhor forma de fazer o pretendido é:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ rm *</div>
<p>Desta forma, o <i>Shell</i> não interpretaria o asterisco, e em conseqüência não faria a sua expansão.</p>
<p>Faça a seguinte experiência científica:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ cd /etc<br />
$ echo &#8216;*&#8217;<br />
$ echo *<br />
$ echo *</div>
<p>Viu a diferença? Então não precisa explicar mais.</p>
<h5><a title="Aspas" name="Aspas"></a><a title="Aspas_" name="Aspas_"></a> Aspas (<code>"</code>)</h5>
<p>Exatamente igual ao apóstrofo exceto que, se a cadeia entre aspas contiver um cifrão (<code>$</code>), uma crase (<code>`</code>), ou uma barra invertida (<code></code>), estes caracteres serão interpretados pelo <i>Shell</i>.</p>
<p>Não precisa se estressar, eu não te dei exemplos do uso das aspas por que você ainda não conhece o cifrão (<code>$</code>) nem a crase (<code>`</code>). Daqui para frente veremos com muita constância o uso destes caracteres especiais, o mais importante é entender o significado de cada um.</p>
<h4><a title="Caracteres_de_redirecionamento" name="Caracteres_de_redirecionamento"></a> Caracteres de redirecionamento</h4>
<p>A maioria dos comandos tem uma entrada, uma saída e pode gerar erros. Esta entrada é chamada Entrada Padrão ou <code>stdin</code> e seu <i>default</i> é o teclado do terminal. Analogamente, a saída do comando é chamada Saída Padrão ou <code>stdout</code> e seu <i>default</i> é a tela do terminal. Para a tela também são enviadas por <i>default</i> as mensagens de erro oriundas do comando que neste caso é a chamada Saída de Erro Padrão ou <code>stderr</code>. Veremos agora como alterar este estado de coisas.</p>
<p>Vamos fazer um programa gago. Para isto faça:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ cat</div>
<p>O <code>cat</code> é uma instrução que lista o conteúdo do arquivo especificado para a Saída Padrão (<code>stdout</code>). Caso a entrada não seja definida, ele espera os dados da <code>stdin</code>. Ora como eu não especifiquei a entrada, ele está esperando-a pelo teclado (Entrada Padrão) e como também não citei a saída, o que eu teclar irá para a tela (Saída Padrão) fazendo desta forma, como eu havia proposto um programa gago. Experimente!</p>
<h5><a title="Redirecionamento_da_Sa�da_Padrão" name="Redirecionamento_da_Sa�da_Padrão"></a> Redirecionamento da Saída Padrão</h5>
<p>Para especificarmos a saída de um programa usamos o <code>&gt;</code> (maior que) ou o <code>&gt;&gt;</code> (maior, maior) seguido do nome do arquivo para o qual se deseja mandar a saída.</p>
<p>Vamos transformar o programa gago em um editor de textos (que pretensão heim!). <img src="http://twiki.softwarelivre.org/pub/TWiki/SmiliesPlugin/smile.gif" alt="smile" border="0" /></p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ cat &gt; Arq</div>
<p>O <code>cat</code> continua sem ter a entrada especificada, portanto está aguardando que os dados sejam teclados, porém a sua saída está sendo desviada para o arquivo <code>Arq</code>. Assim sendo, tudo que esta sendo teclado esta indo para dentro de <code>Arq</code>, de forma que fizemos o editor de textos mais curto e ruim do planeta.</p>
<p>Se eu fizer novamente:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ cat &gt; Arq</div>
<p>Os dados contidos em <code>Arq</code> serão perdidos, já que antes do redirecionamento o <i>Shell</i> criará um <code>Arq</code> vazio. Para colocar mais informações no final do arquivo eu deveria ter feito:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ cat &gt;&gt; Arq</div>
<div style="border:1px dashed red;min-height:105px;background-color:#ffffcc;margin:1em;padding:1em;"><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_atencao.gif" style="float:left;padding:0 8px 0 0;" alt="Pinguim com placa de atenção" /> Como já havia lhe dito, o <i>Shell</i> resolve a linha e depois manda o comando para a execução. Assim, se você redirecionar a saída de um arquivo para ele próprio, primeiramente o <i>Shell</i> &#8220;esvazia&#8221; este arquivo e depois manda o comando para execução, desta forma você acabou de perder o conteúdo do seu querido arquivo.</div>
<p>Com isso dá para notar que o <code>&gt;&gt;</code> (maior maior) serve para inserir texto no final do arquivo.</p>
<h5><a title="Redirecionamento_da_Sa�da_de_Err" name="Redirecionamento_da_Sa�da_de_Err"></a> Redirecionamento da Saída de Erro Padrão</h5>
<p>Assim como o <i>default</i> do <i>Shell</i> é receber os dados do teclado e mandar as saídas para a tela, os erros também serão enviados para a tela se você não especificar para onde deverão ser enviados. Para redirecionar os erros use <code>2&gt; SaidaDeErro</code>. Note que entre o número <code>2</code> e o sinal de maior (<code>&gt;</code>) não existe espaço em branco.</p>
<div style="border:1px dashed red;min-height:105px;background-color:#ffffcc;margin:1em;padding:1em;"><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_atencao.gif" style="float:left;padding:0 8px 0 0;" alt="Pinguim com placa de atenção" /> Preste atenção! Não confunda <code>&gt;&gt;</code> com <code>2&gt;</code>. O primeiro anexa dados ao final de um arquivo, e o segundo redireciona a Saída de Erro Padrão (<code>stderr</code>) para um arquivo que está sendo designado. <b>Isso é importante!</b></div>
<p>Suponha que durante a execução de um <i>script</i> você pode, ou não (dependendo do rumo tomado pela execução do programa), ter criado um arquivo chamado <code>/tmp/seraqueexiste$$</code>. Para não ficar sujeira no seu disco, ao final do <i>script</i> você colocaria uma linha:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ rm /tmp/seraqueexiste$$</div>
<p>Caso o arquivo não existisse seria enviado para a tela uma mensagem de erro. Para que isso não aconteça deve-se fazer:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ rm /tmp/seraqueexiste$$ 2&gt; /dev/null</div>
<p>Sobre o exemplo que acabamos de ver tenho duas dicas a dar:</p>
<div style="border:1px dashed red;min-height:121px;background-color:#ffffcc;margin:1em;padding:1em;"><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" style="float:left;padding:0 8px 0 0;" alt="Pinguim com placa de dica" align="left" /> <b>Dica # 1</b> O <code>$$</code> contém o PID, isto é, o número do seu processo. Como o <i>Linux</i> é multiusuário, é bom anexar sempre o <code>$$</code> ao nome dos dos arquivos que serão usados por várias pessoas para não haver problema de propriedade, isto é, caso você batizasse o seu arquivo simplesmente como <code>seraqueexiste</code>, o primeiro que o usasse (criando-o então) seria o seu dono e todos os outros ganhariam um erro quando tentassem gravar algo nele.</div>
<p>Para que você teste a Saída de Erro Padrão direto no <i>prompt</i> do seu <i>Shell</i>, vou dar mais um exemplo. Faça:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ ls naoexiste<br />
<font color="#ffffff">bash: naoexiste no such file or directory</font><br />
$ ls naoexiste 2&gt; arquivodeerros<br />
$<br />
$ cat arquivodeerros<br />
<font color="#ffffff">bash: naoexiste no such file or directory</font></div>
<p>Neste exemplo, vimos que quando fizemos um <code>ls</code> em <code>naoexiste</code>, ganhamos uma mensagem de erro. Após, redirecionarmos a Saída de Erro Padrão para <code>arquivodeerros</code> e executarmos o mesmo comando, recebemos somente o <i>prompt</i> na tela. Quando listamos o conteúdo do arquivo para o qual foi redirecionada a Saída de Erro Padrão, vimos que a mensagem de erro tinha sido armazenada nele. Faça este teste ai.</p>
<div style="border:1px dashed red;min-height:121px;background-color:#ffffcc;margin:1em;padding:1em;"><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" style="float:left;padding:0 8px 0 0;" alt="Pinguim com placa de dica" align="left" /> <b>Dica # 2</b>     &#8211; Quem é esse tal de <code>/dev/null</code>?- Em <i>Unix</i> existe um arquivo fantasma. Chama-se <code>/dev/null</code>. Tudo que é mandado para este arquivo some. Assemelha-se a um Buraco Negro. No caso do exemplo, como não me interessava guardar a possível mensagem de erro oriunda do comando <code>rm</code>, redirecionei-a para este arquivo.</div>
<p>É interessante notar que estes caracteres de redirecionamento são cumulativos, isto é, se no exemplo anterior fizéssemos:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ ls naoexiste 2&gt;&gt; arquivodeerros</div>
<p>a mensagem de erro oriunda do <code>ls</code> seria anexada ao final de <code>arquivodeerros</code>.</p>
<h5><a title="Redirecionamento_da_Entrada_Padr" name="Redirecionamento_da_Entrada_Padr"></a> Redirecionamento da Entrada Padrão</h5>
<p>Para fazermos o redirecionamento da Entrada Padrão usamos o <code>&lt;</code> (menor que).</p>
<p>- E prá que serve isso? &#8211; você vai me perguntar.</p>
<p>- Deixa eu te dar um exemplo que você vai entender rapidinho.</p>
<p>Suponha que você queira mandar um <code>mail</code> para o seu chefe. Para o chefe nós caprichamos, né?  então ao invés de sair redigindo o <code>mail</code> direto no <i>prompt</i> da tela de forma a tornar impossível a correção de uma frase anterior onde, sem querer, escreveu um &#8220;nós vai&#8221;, você edita um arquivo com o conteúdo da mensagem e após umas quinze verificações sem constatar nenhum erro, decide enviá-lo e para tal faz:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ mail chefe &lt; arquivocommailparaochefe</div>
<p>O teu chefe então receberá o conteúdo do <code>arquivocommailparaochefe</code>.</p>
<h5><a title="Here_Document" name="Here_Document"></a> Here Document</h5>
<p>Um outro tipo de redirecionamento muito louco que o <i>Shell</i> te permite é o chamado <b><i>here document</i></b>. Ele é representado por <code>&lt;&lt;</code> (menor menor) e serve para indicar ao <i>Shell</i> que o escopo de um comando começa na linha seguinte e termina quando encontra uma linha cujo conteúdo seja unicamente o label que segue o sinal <code>&lt;&lt;</code>.</p>
<p>Veja o fragmento de <i>script</i> a seguir, com uma rotina de <code>ftp</code>:</p>
<pre>    ftp -ivn hostremoto &lt;&lt; fimftp
        user $Usuário $Senha
        binary
        get arquivoremoto
    fimftp</pre>
<p>Neste pedacinho de programa temos um monte de detalhes interessantes:</p>
<ol>
<li> As opções que usei para o <code>ftp</code> (<code>-ivn</code>) servem para ele ir listando tudo que está acontecendo (<code>—v</code> de verbose), para não perguntar se você tem certeza de que deseja transmitir cada arquivo (<code>—i</code> de interactive), e finalmente a opção <code>—n</code> serve para dizer ao <code>ftp</code> para ele não solicitar o usuário e sua senha, pois esses serão informados pela instrução específica (<code>user</code>);</li>
<li> Quando eu usei o <code>&lt;&lt; fimftp</code>, estava dizendo o seguinte para o intérprete:<br />
- Olhe aqui <i>Shell</i>, não se meta em nada a partir daqui até encontrar o label <code>fimftp</code>. Você não entenderia nada, já que são instruções específicas do comando <code>ftp</code> e você não entende nada de <code>ftp</code>.<br />
Se fosse só isso seria simples, mas pelo próprio exemplo dá para ver que existem duas variáveis (<code>$Usuário</code> e <code>$Senha</code>), que o <i>Shell</i> vai resolver antes do redirecionamento. Mas a grande vantagem desse tipo de construção é que ela permite que comandos também sejam interpretados dentro do escopo do <i>here document</i>, o que também contraria o que acabei de dizer. Logo a seguir explico como esse negócio funciona. Agora ainda não dá, está faltando ferramenta.</li>
<li> O comando <code>user</code> é do repertório de instruções do <code>ftp</code> e serve para passar o usuário e a senha que haviam sido lidos em uma rotina anterior a esse fragmento de código e colocados respectivamente nas duas variáveis: <code>$Usuário</code> e <code>$Senha</code>.</li>
<li> O <code>binary</code> é outra instrução do <code>ftp</code>, que serve para indicar que a transferência de <code>arquivoremoto</code> será feita em modo binário, isto é, o conteúdo do arquivo não será interpretado para saber se está em ASCII, EBCDIC, &#8230;</li>
<li> O <code>get arquivoremoto</code> diz ao <code>ftp</code> para pegar esse arquivo em <code>hostremoto</code> e trazê-lo para o nosso host local. Se fosse para mandar o arquivo, usaríamos o comando <code>put</code>.</li>
</ol>
<div style="border:1px dashed red;min-height:105px;background-color:#ffffcc;margin:1em;padding:1em;"><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_atencao.gif" style="float:left;padding:0 8px 0 0;" alt="Pinguim com placa de atenção" /> Um erro muito freqüente no uso de <code>labels</code> (como o <code>fimftp</code> do exemplo anterior) é causado pela presença de espaços em branco antes ou após o mesmo. Fique muito atento quanto a isso, por que este tipo de erro costuma dar uma boa surra no programador, até que seja detectado. Lembre-se: um <code>label</code> que se preze tem que ter uma linha inteira só para ele.</div>
<p>- Está bem, está bem! Eu sei que dei uma viajada e entrei pelos comandos do <code>ftp</code>, fugindo ao nosso assunto que é <i>Shell</i>, mas como é sempre bom aprender e é raro as pessoas estarem disponíveis para ensinar&#8230;</p>
<h5><a title="Redirecionamento_de_Comandos" name="Redirecionamento_de_Comandos"></a> Redirecionamento de Comandos</h5>
<p>Os redirecionamentos que falamos até aqui sempre se referiam a arquivos, isto é mandavam para arquivo, recebiam de arquivo, simulavam arquivo local, &#8230; O que veremos a partir de agora redireciona a saída de um comando para a entrada de outro. É utilíssimo e quebra os maiores galhos. Seu nome é <i>pipe</i> (que em inglês significa tubo, já que ele encana a saída de um comando para a entrada de outro) e sua representação é uma barra vertical (<code>|</code>).</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ ls | wc -l<br />
<font color="#ffffff">    21</font></div>
<p>O comando <code>ls</code> passou a lista de arquivos para o comando <code>wc</code>, que quando está com a opção <code>–l</code> conta a quantidade de linha que recebeu. Desta forma, podemos afirmar categoricamente que no meu diretório existiam 21 arquivos.</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ cat /etc/passwd |sort | lp</div>
<p>Esta linha de comandos manda a listagem do arquivo <code>/etc/passwd</code> para a entrada do comando <code>sort</code>. Este a classifica e manda-a para o <code>lp</code> que é o gerenciador do <i>spool</i> de impressão.</p>
<h4><a title="Caracteres_de_Ambiente" name="Caracteres_de_Ambiente"></a> Caracteres de Ambiente</h4>
<p>Quando quer priorizar uma expressão você coloca-a entre parênteses não é? Pois é, por causa da aritmética é normal pensarmos deste jeito. Mas em <i>Shell</i> o que prioriza mesmo são as crases (<code>`</code>) e não os parênteses. Vou dar exemplos de uso das crases para você entender melhor.</p>
<p>Eu quero saber quantos usuários estão &#8220;logados&#8221; no computador que eu administro. Eu posso fazer:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ who | wc -l<br />
<font color="#ffffff">    8</font></div>
<p>O comando <code>who</code> passa a lista de usuários conectados para o comando <code>wc –l</code> que conta quantas linhas recebeu e lista a resposta na tela. Pois bem, mas ao invés de ter um oito solto na tela, o que eu quero é que ele esteja no meio de uma frase.</p>
<p>Ora para mandar frases para a tela eu uso o comando <code>echo</code>, então vamos ver como é que fica:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ echo &#8220;Existem who | wc -l usuários conectados&#8221;<br />
<font color="#ffffff">Existem who | wc -l usuários conectados</font></div>
<p>Hi! Olha só, não funcionou! É mesmo, não funcionou e não foi por causa das aspas que eu coloquei, mas sim por que eu teria que ter executado o <code>who | wc -l</code> antes do <code>echo</code>. Para resolver este problema, tenho que priorizar esta segunda parte do comando com o uso de crases, fazendo assim:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ echo &#8220;Existem `who | wc -l` usuários conectados&#8221;<br />
<font color="#ffffff">Existem     8 usuários conectados</font></div>
<p>Para eliminar esse monte de brancos antes do <code>8</code> que o <code>wc -l</code> produziu, basta tirar as aspas. Assim:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ echo Existem `who | wc -l` usuários conectados<br />
<font color="#ffffff">Existem 8 usuários conectados</font></div>
<p>Como eu disse antes, as aspas protegem tudo que esta dentro dos seus limites, da interpretação do <i>Shell</i>. Como para o <i>Shell</i> basta um espaço em branco como separador, o monte de espaços será trocado por um único após a retirada das aspas.</p>
<p>Antes de falar sobre o uso dos parênteses deixa eu mandar uma rapidinha sobre o uso de ponto-e-vírgula (<code>;</code>). Quando estiver no <i>Shell</i>, você deve sempre dar um comando em cada linha. Para agrupar comandos em uma mesma linha teremos que separá-los por ponto-e-vírgula. Então:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ pwd ; cd /etc; pwd; cd -; pwd<br />
<font color="#ffffff">/home/meudir<br />
/etc/<br />
/home/meudir</font></div>
<p>Neste exemplo, listei o nome do diretório corrente com o comando <code>pwd</code>, mudei para o diretório <code>/etc</code>, novamente listei o nome do diretório e finalmente voltei para o diretório onde estava anteriormente (<code>cd -</code>), listando seu nome. Repare que coloquei o ponto-e-vírgula (<code>;</code>) de todas as formas possíveis para mostrar que não importa se existe espaços em branco antes ou após este caractere.</p>
<p>Finalmente vamos ver o caso dos parênteses. Veja só o caso a seguir, bem parecido com o exemplo anterior:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ (pwd ; cd /etc ; pwd;)<font color="#ffffff"><br />
/home/meudir<br />
/etc/</font><br />
$ pwd<font color="#ffffff"><br />
/home/meudir</font></div>
<p>- Quequeiiisso minha gente? Eu estava no <code>/home/meudir</code>, mudei para o <code>/etc</code>, constatei que estava neste diretório com o <code>pwd</code> seguinte e quando o agrupamento de comandos terminou, eu vi que continuava no <code>/home/meudir</code>, como se eu nunca houvesse saído de lá!</p>
<p>- Ih! Será que é tem coisa de mágico aí?</p>
<p>- Tá me estranhando, rapaz? Não é nada disso! O interessante do uso de parênteses é que ele invoca um novo <i>Shell</i> para executar os comandos que estão no seu interior. Desta forma, realmente fomos para o diretório <code>/etc</code>, porém quando todos os comandos dentro dos parênteses foram executados, o novo <i>Shell</i> que estava no diretório <code>/etc</code> morreu e voltamos ao <i>Shell</i> anterior cujo diretório corrente era <code>/home/meudir</code>. Faça outros testes usando <code>cd</code>, e <code>ls</code> para você firmar o conceito.</p>
<p>Agora que já conhecemos estes conceitos veja só este exemplo a seguir:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ mail suporte &lt;&lt; FIM<br />
&gt; Ola suporte, hoje as ‘date &#8220;+%H:%M&#8221;‘<br />
&gt; ocorreu novamente aquele problema<br />
&gt; que eu havia reportado por<br />
&gt; telefone. Conforme seu pedido<br />
&gt; ai vai uma listagem dos arquivos<br />
&gt; do diretorio:<br />
&gt; ‘ls —l‘<br />
&gt; Abracos a todos.<br />
&gt; FIM</div>
<p>Finalmente agora temos conhecimento para mostrar o que havíamos conversado sobre <b><i>here document</i></b>. Os comandos entre crases (<code>`</code>) serão priorizados e portanto o <i>Shell</i> os executará antes da instrução <code>mail</code>. Quando o suporte receber o <i>e-mail</i>, verá que os comandos <code>date</code> e <code>ls</code> foram executados imediatamente antes do comando <code>mail</code>, recebendo então uma fotografia do ambiente no momento em que a correspondência foi enviada.</p>
<p>O <i>prompt</i> primário <i>default</i> do <i>Shell</i>, como vimos, é o cifrão (<code>$</code>), porém o <i>Shell</i> usa o conceito de <i>prompt</i> secundário, ou de continuação de comando, que é enviado para a tela quando há uma quebra de linha e a instrução não terminou. Esse <i>prompt</i>, é representado por um sinal de maior (<code>&gt;</code>), que vemos precedendo a partir da 2ª linha do exemplo.</p>
<p>Para finalizar e bagunçar tudo, devo dizer que existe uma construção mais moderna que vem sendo utilizada como forma de priorização de execução de comandos, tal qual as crases (<code>`</code>). São as construções do tipo <code>$(cmd)</code>, onde <code>cmd</code> é um (ou vários) comando que será(ão) executado(s) com prioridade em seu contexto.</p>
<p>Assim sendo, o uso de crases (<code>`</code>) ou construções do tipo <code>$(cmd)</code> servem para o mesmo fim, porém para quem trabalha com sistemas operacionais de diversos fornecedores (multiplataforma), aconselho o uso das crases, já que o <code>$(cmd)</code> não foi portado para todos os sabores de <i>Shell</i>. Aqui dentro do Botequim, usarei ambas as formas, indistintamente.</p>
<p>Vejamos novamente o exemplo dado para as crases sob esta nova ótica:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ echo Existem $(who | wc -l) usuários conectados<br />
<font color="#ffffff">Existem 8 usuários conectados</font></div>
<p>Veja só este caso:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ Arqs=ls<br />
$ echo $Arqs<br />
<font color="#ffffff">ls</font></div>
<p>Neste exemplo eu fiz uma atribuição (<code>=</code>) e executei uma instrução. O que eu queria era que a variável <code>$Arqs</code>, recebesse a saída do comando <code>ls</code>. Como as instruções de um <i>script</i> são interpretadas de cima para baixo e da esquerda para a direita, a atribuição foi feita antes da execução do <code>ls</code>. Para fazer o que desejamos é necessário que eu priorize a execução deste comando em detrimento da atribuição e isto pode ser feito de qualquer uma das maneiras a seguir:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ Arqs=`ls`</div>
<p>ou:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ Arqs=$(ls)</div>
<p>Para encerrar este assunto vamos ver só mais um exemplo. Digamos que eu queira colocar dentro da variável <code>$Arqs</code> a listagem longa (<code>ls -l</code>) de todos os arquivos começados por <code>arq</code> e seguidos de um único caractere (<code>?</code>). Eu deveria fazer:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ Arqs=$(ls -l arq?)</div>
<p>ou:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ Arqs=`ls -l arq?`</div>
<p>Mas veja:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ echo $Arqs<br />
<font color="#ffffff">-rw-r&#8211;r&#8211;<br />
1 jneves jneves 19 May 24 19:41 arq1 -rw-r&#8211;r&#8211; 1 jneves jneves 23 May<br />
24 19:43 arq2 -rw-r&#8211;r&#8211; 1 jneves jneves 1866 Jan 22 2003 arql</font></div>
<p>- Pô, saiu tudo embolado!</p>
<p>- Pois é cara, como eu já te disse, se você deixar o <i>Shell</i> “ver” os espaços em branco, sempre que houver diversos espaços juntos, eles serão trocados por apenas um. Para que a listagem saia bonitinha, é necessário proteger a variável da interpretação do <i>Shell</i>, assim:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ echo &#8220;$Arqs&#8221;<br />
<font color="#ffffff">-rw-r&#8211;r&#8211;    1 jneves   jneves         19 May 24 19:41 arq1<br />
-rw-r&#8211;r&#8211;    1 jneves   jneves         23 May 24 19:43 arq2<br />
-rw-r&#8211;r&#8211;    1 jneves   jneves       1866 Jan 22  2003 arql</font></div>
<p>- Olhe, amigo, vá treinando esses exemplos, porque, quando nos encontrarmos novamente, vou lhe explicar uma série de instruções típicas de programação <i>Shell</i>. Tchau! Ahh! Só mais uma coisinha que eu ia esquecendo de lhe dizer. Em <i>Shell</i>, o &#8220;jogo da velha&#8221; (<code>#</code>) é usado quando desejamos fazer um comentário.</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;"> $ exit # pede a conta ao garcon <img src="http://twiki.softwarelivre.org/pub/TWiki/SmiliesPlugin/frown.gif" alt="frown" border="0" /></div>
<p>Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em <i>Shell</i> que mande um e-mail para a nossa <a href="mailto:treinamentos@festivalsoftwarelivre.org?Subject=Curso%20de%20Shell%20com%20Julio%20Neves">gerencia de treinamento</a> para informar-se.</p>
<p>Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para <a href="mailto:julioneves@openoffice.org?Subject=D%C3%BAvidas%20Papo%20de%20Botequim">mim</a>.</p>
<p>Valeu!</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/jneves.wordpress.com/17/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/jneves.wordpress.com/17/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jneves.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jneves.wordpress.com/17/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jneves.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jneves.wordpress.com/17/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jneves.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jneves.wordpress.com/17/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jneves.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jneves.wordpress.com/17/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jneves.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jneves.wordpress.com/17/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jneves.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jneves.wordpress.com/17/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jneves.wordpress.com/17/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jneves.wordpress.com/17/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=17&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-1/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/53f0649d2d6a9b19b90abd0575ee5c7c?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">jneves</media:title>
		</media:content>

		<media:content url="http://jneves.files.wordpress.com/2008/03/julio-neves.jpg" medium="image">
			<media:title type="html">julio-neves.jpg</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/grafico.png" medium="image">
			<media:title type="html">Visão do shell em relação do Kernel do Linux</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" medium="image">
			<media:title type="html">Pinguim com placa de dica</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" medium="image">
			<media:title type="html">Pinguim com placa de dica</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWiki/SmiliesPlugin/smile.gif" medium="image">
			<media:title type="html">smile</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_atencao.gif" medium="image">
			<media:title type="html">Pinguim com placa de atenção</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_atencao.gif" medium="image">
			<media:title type="html">Pinguim com placa de atenção</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" medium="image">
			<media:title type="html">Pinguim com placa de dica</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" medium="image">
			<media:title type="html">Pinguim com placa de dica</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_atencao.gif" medium="image">
			<media:title type="html">Pinguim com placa de atenção</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWiki/SmiliesPlugin/frown.gif" medium="image">
			<media:title type="html">frown</media:title>
		</media:content>
	</item>
		<item>
		<title>Papo de Botequim &#8211; Parte 2</title>
		<link>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-2-2/</link>
		<comments>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-2-2/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 16:38:01 +0000</pubDate>
		<dc:creator>jneves</dc:creator>
				<category><![CDATA[Shell]]></category>
		<category><![CDATA[$]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[cat]]></category>
		<category><![CDATA[chmod]]></category>
		<category><![CDATA[egrep]]></category>
		<category><![CDATA[fgrep]]></category>
		<category><![CDATA[grep]]></category>
		<category><![CDATA[ls]]></category>
		<category><![CDATA[PID]]></category>
		<category><![CDATA[regexp]]></category>
		<category><![CDATA[shift]]></category>
		<category><![CDATA[|]]></category>

		<guid isPermaLink="false">http://jneves.wordpress.com/?p=16</guid>
		<description><![CDATA[Eu fico com o grep, você com a gripe A família grep Vamos Montar uma &#8220;cdteca&#8221; Passando parâmetros Macetes paramétricos - Garçom! Traz um &#8220;chops&#8221; e dois &#8220;pastel&#8221;. O meu amigo hoje não vai beber por que ele finalmente está sendo apresentado a um verdadeiro sistema operacional e ainda tem muita coisa a aprender! - [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=16&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div class="twikiToc">
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo002#Eu_fico_com_o_grep_voc%C3%AA_com_a_gr"> Eu fico com o grep, você com a gripe</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo002#A_fam%C3%ADlia_grep"> A família grep</a></li>
</ul>
</li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo002#Vamos_Montar_uma_cdteca"> Vamos Montar uma &#8220;cdteca&#8221;</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo002#Passando_par%C3%A2metros"> Passando parâmetros</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo002#Macetes_param%C3%A9tricos"> Macetes paramétricos</a></li>
</ul>
</li>
</ul>
</div>
<p>- Garçom! Traz um &#8220;chops&#8221; e dois &#8220;pastel&#8221;. O meu amigo hoje não vai beber por que ele finalmente está sendo apresentado a um verdadeiro sistema operacional e ainda tem muita coisa a aprender!<br />
- E então, amigo, tá entendendo tudo que te expliquei até agora?<br />
- Entendendo eu tô, mas não vi nada prático nisso&#8230;<br />
- 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 <i>Shell</i> permite. Você verá porque até na TV já teve programa chamado &#8220;O <i>Shell</i> é o Limite&#8221;.<br />
- Para começar vamos falar dos comandos da família <code>grep</code>.<br />
- <code>grep</code>? Não conheço nenhum termo em inglês com este nome&#8230;<br />
- É claro, <code>grep</code> é um acrônimo <b>Global Regular Expression Print</b>, que usa expressões regulares para pesquisar a ocorrência de cadeias de caracteres na entrada definida (se bem que há uma lenda sobre como este comando foi nomeado: no editor de textos &#8220;ed&#8221;, o avô do &#8220;vim&#8221;, o comando usado para buscas era g/_expressao regular_/p, ou no inglês g/_re_/p.). Por falar em expressões regulares (ou <b>regexp</b>), o <a href="http://www.google.com.br/search?num=100&amp;hl=pt-BR&amp;as_qdr=all&amp;q=%2B%22%5E+EXPRESS%C3%95ES+REGULARES+%24%22+%2Blego+%2B%22como+farejar+um+texto%22&amp;btnG=Pesquisar&amp;meta=" target="_blank">Aurélio Marinho Jargas</a> tem todas as dicas em sua página (inclusive tutorias) que abordam o tema. Se você está mesmo a fim de aprender a programar em <b>Shell</b>, <b>Perl</b>, <b>Python</b>, &#8230; Acho bom você ler estes artigos para te ajudar no que está para vir.</p>
<h2><a title="Eu_fico_com_o_grep_você_com_a_gr" name="Eu_fico_com_o_grep_você_com_a_gr"></a> Eu fico com o <code>grep</code>, você com a gripe</h2>
<p>Esse negócio de gripe é brincadeira! É só um pretexto para pedir umas caipirinhas. Mas voltando à vaca fria, eu te falei que o <code>grep</code> procura cadeia de caracteres dentro de uma entrada definida, mas o que vem a ser uma &#8220;entrada definida&#8221;? Bem, existem várias formas de definir a entrada do comando <code>grep</code>. Vejamos: Pesquisando em um arquivo:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ grep rafael /etc/passwd</div>
<p>Pesquisando em vários arquivos:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ grep grep *.sh</div>
<p>Pesquisando na saida de comando:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ who | grep Pelegrino</div>
<p>No 1º exemplo, o mais simples, procurei a palavra rafael em qualquer lugar do arquivo <code>/etc/passwd</code>. Se quisesse procurá-la como um login name, isto é, somente no início dos registros deste arquivo, eu deveria fazer:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ grep &#8216;^rafael&#8217; /etc/passwd</div>
<p>E para que serve este circunflexo e os apóstrofos, você vai me perguntar. O circunflexo (<code>^</code>), se você tivesse lido os artigos anteriores sobre expressões regulares que te falei, saberia que servem para limitar a pesquisa ao início de cada linha, e os apóstrofos (<code>'</code>) servem para o <i>Shell</i> não interpretar este circunflexo, deixando-o passar incólume para o comando <code>grep</code>.</p>
<p>Olha que legal! O <code>grep</code> aceita como entrada, a saída de outro comando redirecionado por um <code>pipe</code> (isto é muito comum em <i>Shell</i> e é um tremendo acelerador de execução de comando já que atua como se a saída de um programa fosse guardada em disco e o segundo programa lesse este arquivo gerado), desta forma, no 3º exemplo, o comando <code>who</code> listou as pessoas &#8220;logadas&#8221; na mesma máquina que você (não se esqueça jamais: o <i>Linux</i> é multiusuário) e o <code>grep</code> foi usado para verificar se o Pelegrino estava trabalhando ou &#8220;coçando&#8221;.</p>
<h3><a title="A_fam�lia_grep" name="A_fam�lia_grep"></a><a title="A_fam�lia_grep_" name="A_fam�lia_grep_"></a> A família <code>grep</code></h3>
<p>Este comando <code>grep</code> é muito conhecido, pois é usado com muita freqüência, o que muitas pessoas desconhecem é que existem três comandos na família <code>grep</code>, que são:</p>
<ul>
<li> <code>grep</code></li>
<li> <code>egrep</code></li>
<li> <code>fgrep</code></li>
</ul>
<p>A principais características diferenciais entre os 3 são:</p>
<ul>
<li> O <code>grep</code> pode ou não usar expressões regulares simples, porém no caso de não usá-las, o <code>fgrep</code> é melhor, por ser mais rápido;</li>
<li> O <code>egrep</code> (&#8220;e&#8221; de extended, extendido) é muito poderoso no uso de expressões regulares. Por ser o mais lento da família, só deve ser usado quando for necessária a elaboração de uma expressão regular não aceita pelo <code>grep</code>;</li>
<li> O <code>fgrep</code> (&#8220;f&#8221; de fast, rápido, ou de &#8220;file&#8221;, arquivo) como o nome diz é o rapidinho da família, executa o serviço de forma muito veloz (por vezes é cerca de 30% mais veloz que o grep e 50% mais que o egrep), porém não permite o uso de expressões regulares na pesquisa.</li>
</ul>
<div style="border:1px dashed red;min-height:105px;background-color:#ffffcc;margin:1em;padding:1em;"><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_atencao.gif" style="float:left;padding:0 8px 0 0;" alt="Pinguim com placa de atenção" /> Tudo que foi dito acima sobre velocidade, só se aplica à família de comandos <code>grep</code> do <i>Unix</i>. No <i>Linux</i> o <code>grep</code> é sempre mais veloz, já que os outros dois (<code>fgrep</code> e <code>egrep</code>) são <i>scripts</i> em <i>Shell</i> que chamam o primeiro e, já vou adiantando, <b>não gosto</b> nem um pouquinho desta solução.</div>
<p>- Agora que você já conhece as diferenças entre os membros da família, me diga: o que você acha dos três exemplos que eu dei antes das explicações?<br />
- Eu achei que o <code>fgrep</code> resolveria o teu problema de forma mais veloz do que o <code>grep</code>.<br />
- Perfeito! Tô vendo que você está atento! Está entendendo tudo que estou te explicando! Então vamos ver mais exemplos para clarear de vez as diferenças de uso dos membros da família.<br />
Exemplos</p>
<p>Eu sei que em um arquivo existe um texto falando sobre <code>Linux</code> só não tenho certeza se está escrito com <code>L</code> maiúsculo ou <code>l</code> minúsculo. Posso fazer de duas formas:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ egrep (Linux | linux) arquivo.txt</div>
<p>ou</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ grep [Ll]inux arquivo.txt</div>
<p>No primeiro caso, a expressão regular complexa <code>"(Linux | linux)"</code> usa os parênteses para agrupar as opções e a barra vertical (<code>|</code>) como um &#8220;ou&#8221; lógico, isto é, estou procurando <code>Linux</code> ou <code>linux</code>.</p>
<p>No segundo, a expressão regular <code>[Ll]inux</code> significa: começado por <code>L</code> ou <code>l</code> seguido de <code>inux</code>. Por esta expressão ser mais simples, o <code>grep</code> consegue resolvê-la, portanto acho melhor usar a segunda forma, já que o <code>egrep</code> tornaria a pesquisa mais lenta.</p>
<p>Outro exemplo. Para listar todos os subdiretórios do diretório corrente, basta:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ ls -l | grep &#8216;^d&#8217;<font color="#ffffff"><br />
drwxr-xr-x   3 root     root         4096 Dec 18  2000 doc<br />
drwxr-xr-x  11 root     root         4096 Jul 13 18:58 freeciv<br />
drwxr-xr-x   3 root     root         4096 Oct 17  2000 gimp<br />
drwxr-xr-x   3 root     root         4096 Aug  8  2000 gnome<br />
drwxr-xr-x   2 root     root         4096 Aug  8  2000 idl<br />
drwxrwxr-x  14 root     root         4096 Jul 13 18:58 locale<br />
drwxrwxr-x  12 root     root         4096 Jan 14  2000 lyx<br />
drwxrwxr-x   3 root     root         4096 Jan 17  2000 pixmaps<br />
drwxr-xr-x   3 root     root         4096 Jul  2 20:30 scribus<br />
drwxrwxr-x   3 root     root         4096 Jan 17  2000 sounds<br />
drwxr-xr-x   3 root     root         4096 Dec 18  2000 xine</font></div>
<p>No exemplo que acabamos de ver, o circunflexo (<code>^</code>) serviu para limitar a pesquisa à primeira posição da saída do <code>ls</code> longo. Os apóstrofos foram colocados para o <i>Shell</i> não &#8220;ver&#8221; o circunflexo (<code>^</code>).</p>
<p>Vamos ver mais um. Sabemos que as quatro primeiras posições possíveis de um <code>ls -l</code> de um arquivo comum (arquivo comum! Não é diretório, nem <i>link</i>, nem &#8230;) devem ser:</p>
<table class="twikiTable" border="0" cellpadding="4" cellspacing="1">
<tr>
<th class="twikiFirstCol" align="center" bgcolor="#0000ff"><b><font color="#ffff00">Posição</font></b></th>
<th bgcolor="#0000ff"><b><font color="#ffff00"> 1ª </font></b></th>
<th bgcolor="#0000ff"><b><font color="#ffff00"> 2ª </font></b></th>
<th bgcolor="#0000ff"><b><font color="#ffff00"> 3ª </font></b></th>
<th align="center" bgcolor="#0000ff"><b><font color="#ffff00"> 4ª </font></b></th>
</tr>
<tr>
<td rowspan="3" class="twikiFirstCol" bgcolor="#dddddd">Valores Possíveis</td>
<td align="center" bgcolor="#dddddd"><code>-</code></td>
<td align="center" bgcolor="#dddddd"><code>r</code></td>
<td align="center" bgcolor="#dddddd"><code>w</code></td>
<td align="center" bgcolor="#dddddd"><code>x</code></td>
</tr>
<tr>
<td bgcolor="#bbbbbb">&nbsp;</td>
<td align="center" bgcolor="#bbbbbb"><code>-</code></td>
<td align="center" bgcolor="#bbbbbb"><code>-</code></td>
<td align="center" bgcolor="#bbbbbb"><code>s</code> (suid)</td>
</tr>
<tr>
<td bgcolor="#dddddd">&nbsp;</td>
<td bgcolor="#dddddd">&nbsp;</td>
<td bgcolor="#dddddd">&nbsp;</td>
<td align="center" bgcolor="#dddddd"><code>-</code></td>
</tr>
</table>
<p>Assim sendo, para descobrir todos os arquivos executáveis em um determinado diretório eu deveria fazer:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ ls -la | egrep &#8216;^-..(x|s)&#8217;<font color="#ffffff"><br />
-rwxr-xr-x   1 root     root       2875 Jun 18 19:38 rc<br />
-rwxr-xr-x   1 root     root        857 Aug  9 22:03 rc.local<br />
-rwxr-xr-x   1 root     root      18453 Jul  6 17:28 rc.sysinit</font></div>
<p>Onde novamente usamos o circunflexo (<code>^</code>) para limitar a pesquisa ao início de cada linha, então as linhas listadas serão as que começam por um traço (<code>-</code>), seguido de qualquer coisa (o ponto quando usado como uma expressão regular significa qualquer coisa), novamente seguido de qualquer coisa, vindo a seguir um <code>x</code> ou um <code>s</code>.</p>
<p>Obteríamos o mesmo resultado se fizéssemos:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ ls -la | grep &#8216;^-..[xs]&#8216;</div>
<p>e agilizaríamos a pesquisa.</p>
<h2><a title="Vamos_Montar_uma_cdteca" name="Vamos_Montar_uma_cdteca"></a><a title="Vamos_Montar_uma_cdteca_" name="Vamos_Montar_uma_cdteca_"></a> Vamos Montar uma &#8220;cdteca&#8221;</h2>
<p>Vamos começar a desenvolver programas, acho que a montagem de um banco de dados de músicas é bacana para efeito didático (e útil nesses tempos de <i>downloads</i> de mp3 e &#8220;queimadores&#8221; de CDs). Não se esqueça que, da mesma forma que vamos desenvolver um monte de programas para organizar os seus CDs de música, com pequenas adaptações, você pode fazer o mesmo com os CDs de <i>software</i> que vêm com a <b><i>Linux Magazine</i></b> e outros que você compra ou queima, disponibilizando este banco de <i>software</i> para todos que trabalham com você (o <i>Linux</i> é multiusuário, e como tal deve ser explorado), desta forma ganhando muitos pontos com seu adorado chefe.</p>
<p>- Péra ai! De onde eu vou receber os dados dos CDs?<br />
- Inicialmente, vou lhe mostrar como o seu programa pode receber parâmetros de quem o estiver executando e em breve, ensinarei a ler os dados pela tela ou de um arquivo.</p>
<h3><a title="Passando_parâmetros" name="Passando_parâmetros"></a> Passando parâmetros</h3>
<p>O layout do arquivo musicas será o seguinte:</p>
<p><code>nome do álbum^intérprete1~nome da música1:..:intérprete~nome da música</code></p>
<p>isto é, o nome do álbum será separado por um circunflexo (<code>^</code>) do resto do registro, que é formado por diversos grupos compostos pelo intérprete de cada música do CD e a respectiva música interpretada. Estes grupos são separados entre si por dois-pontos (<code>:</code>) e internamente, o intérprete será separado por um til (<code>~</code>) do nome da música.</p>
<p>Eu quero escrever um programa que chamado <code>musinc</code>, que incluirá registros no meu arquivo musicas. Eu passarei o conteúdo de cada álbum como parâmetro na chamada do programa fazendo assim:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ musinc &#8220;álbum^interprete~musica:interprete~musica:&#8230;&#8221;</div>
<p>Desta forma o programa <code>musinc</code> estará recebendo os dados de cada álbum como se fosse uma variável. A única diferença entre um parâmetro recebido e uma variável é que os primeiros recebem nomes numéricos (nome numérico fica muito esquisito, né? O que quis dizer é que seus nomes são formados por um e somente um algarismo), isto é <code>$1, $2, $3, ..., $9</code>. Vamos, antes de tudo, fazer um teste:</p>
<p>Exemplos</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat teste<br />
<font color="#ffffff">#!/bin/bash<br />
# Programa para testar passagem de parametros<br />
echo &#8220;1o. parm -&gt; $1&#8243;<br />
echo &#8220;2o. parm -&gt; $2&#8243;<br />
echo &#8220;3o. parm -&gt; $3&#8243;</font></div>
<p>Vamos executá-lo:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ teste passando parametros para testar<br />
<font color="#ffffff">bash: teste: cannot execute</font></div>
<p>Ops! Esqueci-me de torná-lo executável. Vou fazê-lo de forma a permitir que todos possam executá-lo e em seguida vou testá-lo:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ chmod 755 teste<br />
$ teste passando parametros para testar<br />
<font color="#ffffff">1o. parm -&gt; passando<br />
2o. parm -&gt; parametros<br />
3o. parm -&gt; para</font></div>
<p>Repare que a palavra <code>testar</code>, que seria o quarto parâmetro, não foi listada. Isto deu-se justamente porque o programa teste só listava os três primeiros parâmetros. Vamos executá-lo de outra forma:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ teste &#8220;passando parametros&#8221; para testar<font color="#ffffff"><br />
1o. parm -&gt; passando parametros<br />
2o. parm -&gt; para<br />
3o. parm -&gt; testar</font></div>
<p>As aspas não deixaram o <code>Shell</code> ver o espaço em branco entre as palavras e considerou-as um único parâmetro.</p>
<h3><a title="Macetes_paramétricos" name="Macetes_paramétricos"></a> Macetes paramétricos</h3>
<p>Já que estamos falando em passagem de parâmetros deixa eu te dar mais umas dicas:</p>
<table class="twikiTable" border="0" cellpadding="4" cellspacing="1">
<tr>
<th colspan="2" class="twikiFirstCol" align="center" bgcolor="#0000ff"><b><font color="#ffff00">Significado das Principais Variáveis Referentes aos Parâmetros</font></b></th>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><b>Variável</b></td>
<td bgcolor="#dddddd"><b>Significado</b></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>$0</code></td>
<td bgcolor="#bbbbbb">Contém o nome do programa</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><code>$#</code></td>
<td bgcolor="#dddddd">Contém a quantidade de parâmetros passados</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>$*</code></td>
<td bgcolor="#bbbbbb">Contém o conjunto de todos os parâmetros (muito parecido com <code>$@</code>)</td>
</tr>
</table>
<p>Exemplos</p>
<p>Vamos alterar o programa <code>teste</code> para usar as variáveis que acabamos de ver. Vamos fazê-lo assim:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat teste<br />
<font color="#ffffff">#!/bin/bash<br />
# Programa para testar passagem de parametros (2a. Versao)<br />
echo O programa $0 recebeu $# parametros<br />
echo &#8220;1o. parm -&gt; $1&#8243;<br />
echo &#8220;2o. parm -&gt; $2&#8243;<br />
echo &#8220;3o. parm -&gt; $3&#8243;<br />
echo Todos de uma só &#8220;tacada&#8221;: $*</font></div>
<p>Repare que antes das aspas eu usei uma barra invertida para o escondê-las da interpretação do <i>Shell</i> (se não usasse as contrabarras as aspas não apareceriam). Vamos executá-lo:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ teste passando parametros para testar<br />
<font color="#ffffff">O programa teste recebeu 4 parametros<br />
1o. parm -&gt; passando<br />
2o. parm -&gt; parametros<br />
3o. parm -&gt; para<br />
Todos de uma só &#8220;tacada&#8221;: passando parametros para testar</font></div>
<p>Conforme eu disse, os parâmetros recebem números de <code>1</code> a  <code>9</code>, mas isso não significa que não posso usar mais de 9 parâmetros significa somente que só posso endereçar 9. Vamos testar isso:</p>
<p>Exemplo:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat teste<br />
<font color="#ffffff">#!/bin/bash<br />
# Programa para testar passagem de parametros (3a. Versao)<br />
echo O programa $0 recebeu $# parametros<br />
echo &#8220;11o. parm -&gt; $11&#8243;<br />
shift<br />
echo &#8220;2o. parm -&gt; $1&#8243;<br />
shift 2<br />
echo &#8220;4o. Parm -&gt; $1&#8243;</font></div>
<p>Vamos executá-lo:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ teste passando parametros para testar<br />
<font color="#ffffff">O programa teste recebeu 4 parametros que são:<br />
11o. parm -&gt; passando1<br />
2o. parm -&gt; parametros<br />
4o. parm -&gt; testar</font></div>
<p>Duas coisas muito interessantes neste <i>script</i>:</p>
<ol>
<li> Para mostrar que os nomes dos parâmetros variam de <code>$1</code> a <code>$9</code> eu fiz um echo <code>$11</code> e o que aconteceu? O <i>Shell</i> interpretou como sendo <code>$1</code> seguido do algarismo <code>1</code> e listou <code>passando1</code>;</li>
<li> O comando <code>shift</code> cuja sintaxe é <code>shift n</code>, podendo o <code>n</code> assumir qualquer valor numérico (porém seu <i>default</i> é <code>1</code> como no exemplo dado), despreza os <code>n</code> primeiros parâmetros, tornando o parâmetro de ordem <code>n+1</code>, o primeiro ou seja, o <code>$1</code>.</li>
</ol>
<p>Bem, agora que você já sabe mais sobre passagem de parâmetros do que eu, vamos voltar à nossa &#8220;cdteca&#8221; para fazer o <i>script</i> de inclusão de CDs no meu banco chamado <code>musicas</code>. O programa é muito simples (como tudo em <i>Shell</i>) e vou listá-lo para você ver:</p>
<p>Exemplos</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat musinc<br />
<font color="#ffffff">#!/bin/bash<br />
# Cadastra CDs (versao 1)<br />
#<br />
echo $1 &gt;&gt; musicas</font></div>
<p>O <i>script</i> é fácil e funcional, limito-me a anexar ao fim do arquivo <code>musicas</code> o parâmetro recebido. Vamos cadastrar 3 álbuns para ver se funciona (para não ficar &#8220;enchendo lingüiça&#8221;, vou supor que em cada CD só existem 2 músicas):</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ musinc &#8220;album 3^Artista5~Musica5:Artista6~Musica5&#8243;<br />
$ musinc &#8220;album 1^Artista1~Musica1:Artista2~Musica2&#8243;<br />
$ musinc &#8220;album 2^Artista3~Musica3:Artista4~Musica4&#8243;</div>
<p>Listando o conteúdo de musicas.</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat musicas<br />
<font color="#ffffff">album 3^Artista5~Musica5:Artista6~Musica6<br />
album 1^Artista1~Musica1:Artista2~Musica2<br />
album 2^Artista3~Musica3:Artista4~Musica4</font></div>
<p>Não está funcional como achava que deveria ficar&#8230; podia ter ficado melhor. Os álbuns estão fora de ordem, dificultando a pesquisa. Vamos alterar nosso <i>script</i> e depois testá-lo novamente:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat musinc<br />
<font color="#ffffff">#!/bin/bash<br />
# Cadastra CDs (versao 2)<br />
#<br />
echo $1 &gt;&gt; musicas<br />
sort musicas -o musicas</font></div>
<p>Vamos cadastrar mais um:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ musinc &#8220;album 4^Artista7~Musica7:Artista8~Musica8&#8243;</div>
<p>Agora vamos ver o que aconteceu com o arquivo <code>musicas</code>:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat musicas<br />
<font color="#ffffff">album 1^Artista1~Musica1:Artista2~Musica2<br />
album 2^Artista3~Musica3:Artista4~Musica4<br />
album 3^Artista5~Musica5:Artista6~Musica5<br />
album 4^Artista7~Musica7:Artista8~Musica8</font></div>
<p>Simplesmente inseri uma linha que classifica o arquivo <code>musicas</code> dando a saída nele mesmo (para isso serve a opção <code>-o</code>), após cada álbum ser anexado.</p>
<p>Oba! Agora está legal e quase funcional. Mas atenção, não se desespere! Esta não é a versão final. O programa ficará muito melhor e mais amigável, em uma nova versão que desenvolveremos após aprendermos a adquirir os dados da tela e formatar a entrada.</p>
<p>Exemplos</p>
<p>Ficar listando com o comando <code>cat</code> não está com nada, vamos então fazer um programa chamado <code>muslist</code> para listar um álbum cujo nome será passado como parâmetro:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat muslist<br />
<font color="#ffffff">#!/bin/bash<br />
# Consulta CDs (versao 1)<br />
#<br />
grep $1 musicas</font></div>
<p>Vamos executá-lo, procurando pelo <code>album 2</code>. Como já vimos antes, para passar a cadeia <code>album 2</code> é necessário protegê-la da interpretação do <i>Shell</i>, para que ele não a interprete como dois parâmetros. Vamos fazer assim:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ muslist &#8220;álbum 2&#8243;<br />
<font color="#ffffff">grep: can&#8217;t open 2<br />
musicas: album 1^Artista1~Musica1:Artista2~Musica2<br />
musicas: album 2^Artista3~Musica3:Artista4~Musica4<br />
musicas: album 3^Artista5~Musica5:Artista6~Musica6<br />
musicas: album 4^Artista7~Musica7:Artista8~Musica8</font></div>
<p>Que lambança! Onde está o erro? Eu tive o cuidado de colocar o parâmetro passado entre aspas, para o <i>Shell</i> não dividi-lo em dois!</p>
<p>É, mas repare como está o <code>grep</code> executado:</p>
<p><code>grep $1 musicas</code></p>
<p>Mesmo colocando <code>álbum 2</code> entre aspas, para que fosse encarado como um único parâmetro, quando o <code>$1</code> foi passado pelo <i>Shell</i> para o comando <code>grep</code>, transformou-se em dois argumentos. Desta forma o conteúdo final da linha, que o comando <code>grep</code> executou foi o seguinte:</p>
<p><code>grep album 2 musicas</code></p>
<p>Como a sintaxe do <code>grep</code> é:</p>
<p>=grep  [arq1, arq2, ..., arqn]=</p>
<p>o <code>grep</code> entendeu que deveria procurar a cadeia de caracteres <code>album</code> nos <code>arquivos 2</code> e <code>musicas</code>, Por não existir o <code>arquivo 2</code> gerou o erro, e por encontrar a palavra <code>album</code> em todos os registros de <code>musicas</code>, listou a todos.</p>
<div style="border:1px dashed red;min-height:121px;background-color:#ffffcc;margin:1em;padding:1em;"><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" style="float:left;padding:0 8px 0 0;" alt="Pinguim com placa de dica" align="left" /> Sempre que a <code>cadeia de caracteres</code> a ser passada para o comando <code>grep</code> possuir brancos ou <code>TAB</code>, mesmo que dentro de variáveis, coloque-a sempre entre aspas para evitar que as palavras após o primeiro espaço em branco ou <code>TAB</code> sejam interpretadas como nomes de arquivos.</div>
<p>Por outro lado, é melhor ignorarmos maiúsculas e minúsculas na pesquisa. Resolveríamos os dois problemas se o programa tivesse a seguinte forma:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat muslist<br />
<font color="#ffffff">#!/bin/bash<br />
# Consulta CDs (versao 2)<br />
#<br />
grep -i &#8220;$1&#8243; musicas</font></div>
<p>Neste caso, usamos a opção <code>-i</code> do <code>grep</code>, que como já vimos, serve para ignorar maiúsculas e minúsculas, e colocamos o <code>$1</code> entre aspas, para que o <code>grep</code> continuasse a ver a cadeia de caracteres resultante da expansão da linha pelo <code>Shell</code> como um único argumento de pesquisa.</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ muslist &#8220;album 2&#8243;<font color="#ffffff"><br />
album2^Artista3~Musica3:Artista4~Musica4</font></div>
<p>Agora repare que o <code>grep</code> localiza a cadeia pesquisada em qualquer lugar do registro, então da forma que estamos fazendo, podemos pesquisar por álbum, por música, por intérprete ou até por um pedaço de qualquer um destes. Quando conhecermos os comandos condicionais, montaremos uma nova versão de <code>muslist</code> que permitirá especificar por qual campo pesquisar.</p>
<p>Aí você vai me dizer:</p>
<p>- Poxa, mas é um saco ter que colocar o argumento de pesquisa entre aspas na hora de passar o nome do álbum. Esta forma não é nem um pouco amigável!<br />
- Tem razão, e por isso vou te mostrar uma outra forma de fazer o que você pediu:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat muslist<br />
<font color="#ffffff">#!/bin/bash<br />
# Consulta CDs (versao 3)<br />
#<br />
grep -i &#8220;$*&#8221; musicas<br />
$ muslist album 2<br />
album 2^Artista3~Musica3:Artista4~Musica4</font></div>
<p>Desta forma, o <code>$*</code>, que significa todos os parâmetros, será substituído pela cadeia <code>album 2</code> (de acordo com o exemplo anterior, fazendo o que você queria.</p>
<p>Não se esqueça o problema do <i>Shell</i> não é se você pode ou não fazer uma determinada coisa. O problema é decidir qual é a melhor forma de fazê-la, já que para desempenhar qualquer tarefa, a quantidade de opções é enorme.</p>
<p>Ah! Em um dia de verão você foi à praia, esqueceu o CD no carro, aquele &#8220;solzinho&#8221; de 40 graus empenou o seu CD e agora você precisa de uma ferramenta para removê-lo do banco de dados? Não tem problema, vamos desenvolver um <i>script</i> chamado <code>musexc</code>, para excluir estes CDs.</p>
<p>Antes de desenvolver o &#8220;bacalho&#8221;, quero te apresentar a uma opção bastante útil da família de comandos <code>grep</code>. É a opção <code>-v</code>, que quando usada lista todos os registros da entrada, exceto o(s) localizado(s) pelo comando. Vejamos:</p>
<p>Exemplos</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ grep -v &#8220;album 2&#8243; musicas<br />
<font color="#ffffff">album 1^Artista1~Musica1:Artista2~Musica2<br />
album 3^Artista5~Musica5:Artista6~Musica6<br />
album 4^Artista7~Musica7:Artista8~Musica8</font></div>
<p>Conforme eu expliquei antes, o <code>grep</code> do exemplo listou todos os registros de musicas exceto o referente a <code>album 2</code>, porque atendia ao argumento do comando. Estamos então prontos para desenvolver o <i>script</i> para remover aquele CD empenado da sua &#8220;CDteca&#8221;. Ele tem a seguinte cara:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat musexc<br />
<font color="#ffffff">#!/bin/bash<br />
# Exclui CDs (versao 1)<br />
#<br />
grep -v &#8220;$1&#8243; musicas &gt; /tmp/mus$$<br />
mv -f /tmp/mus$$ musicas</font></div>
<p>Na primeira linha mandei para <code>/tmp/mus$$</code> o arquivo musicas, sem os registros que atendessem a consulta feita pelo comando <code>grep</code>. Em seguida, movi (que, no duro, equivale a renomear) <code>/tmp/mus$$</code> por cima do antigo <code>musicas</code>.</p>
<p>Usei o arquivo <code>/tmp/mus$$</code> como arquivo de trabalho, porque como já havia citado no artigo anterior, o <code>$$</code> contém o <code>PID</code> (<i>Process Identification</i> ou identificação do processo) e desta forma cada um que editar o arquivo <code>musicas</code> o fará em um arquivo de trabalho diferente, desta forma evitando colisões no uso.</p>
<p>- Aê cara, estes programas que fizemos até aqui estão muito primários em virtude da falta de ferramentas que ainda temos. Mas é bom, enquanto eu tomo mais um chope, você ir para casa praticar em cima dos exemplos dados porque, eu prometo, chegaremos a desenvolver um sistema bacana para controle dos seus CDs.<br />
- Quando nos encontrarmos da próxima vez, vou te ensinar como funcionam os comandos condicionais e aprimoraremos mais um pouco estes <i>scripts</i>.<br />
- Por hoje chega! Já falei demais e preciso molhar a palavra porque estou de goela seca!<br />
- Garçom! Mais um sem colarinho!</p>
<p>Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em <i>Shell</i> que mande um e-mail para a nossa <a href="mailto:treinamentos@festivalsoftwarelivre.org?Subject=Curso%20de%20Shell%20com%20Julio%20Neves">gerencia de treinamento</a> para informar-se.</p>
<p>Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para <a href="mailto:julioneves@openoffice.org?Subject=D%C3%BAvidas%20Papo%20de%20Botequim">mim</a>.</p>
<p>Valeu!</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/jneves.wordpress.com/16/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/jneves.wordpress.com/16/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jneves.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jneves.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jneves.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jneves.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jneves.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jneves.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jneves.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jneves.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jneves.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jneves.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jneves.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jneves.wordpress.com/16/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jneves.wordpress.com/16/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jneves.wordpress.com/16/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=16&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-2-2/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/53f0649d2d6a9b19b90abd0575ee5c7c?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">jneves</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_atencao.gif" medium="image">
			<media:title type="html">Pinguim com placa de atenção</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" medium="image">
			<media:title type="html">Pinguim com placa de dica</media:title>
		</media:content>
	</item>
		<item>
		<title>Papo de Botequim &#8211; Parte 3</title>
		<link>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-3/</link>
		<comments>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-3/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 16:34:11 +0000</pubDate>
		<dc:creator>jneves</dc:creator>
				<category><![CDATA[Shell]]></category>
		<category><![CDATA[grep]]></category>
		<category><![CDATA[cut]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[cat]]></category>
		<category><![CDATA[sort]]></category>
		<category><![CDATA[if]]></category>
		<category><![CDATA[echo]]></category>
		<category><![CDATA[seq]]></category>
		<category><![CDATA[paste]]></category>
		<category><![CDATA[tr]]></category>
		<category><![CDATA[head]]></category>
		<category><![CDATA[date]]></category>
		<category><![CDATA[mv]]></category>
		<category><![CDATA[$]]></category>

		<guid isPermaLink="false">http://jneves.wordpress.com/?p=15</guid>
		<description><![CDATA[Trabalhando com cadeias O Comando cut (que não é a central de trabalhadores) O comando cut com a opção -c O comando cut com a opção -f Se tem cut tem paste Quem está em pé, deita Usando separadores O Comando tr Trocando caracteres com tr Removendo caracteres com tr Xpremendo com tr Comandos Condicionais [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=15&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div class="twikiToc">
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo003#Trabalhando_com_cadeias"> Trabalhando com cadeias</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo003#O_Comando_cut_que_n%C3%A3o_%C3%A9_a_centra"> O Comando cut (que não é a central de trabalhadores) <!--pula duas linhas--></a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo003#O_comando_cut_com_a_op%C3%A7%C3%A3o_c"> O comando cut com a opção -c</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo003#O_comando_cut_com_a_op%C3%A7%C3%A3o_f"> O comando cut com a opção -f</a></li>
</ul>
</li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo003#Se_tem_cut_tem_paste"> Se tem cut tem paste</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo003#Quem_est%C3%A1_em_p%C3%A9_deita"> Quem está em pé, deita</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo003#Usando_separadores"> Usando separadores</a></li>
</ul>
</li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo003#O_Comando_tr"> O Comando tr</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo003#Trocando_caracteres_com_tr">  Trocando caracteres com tr</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo003#Removendo_caracteres_com_tr">  Removendo caracteres com tr</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo003#Xpremendo_com_tr"> Xpremendo com tr</a></li>
</ul>
</li>
</ul>
</li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo003#Comandos_Condicionais"> Comandos Condicionais</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo003#O_Comando_if"> O Comando if</a></li>
</ul>
</li>
</ul>
</div>
<p>- Garçon, traga dois chopes por favor que hoje eu vou ter que falar muito.</p>
<h2><a title="Trabalhando_com_cadeias" name="Trabalhando_com_cadeias"></a> Trabalhando com cadeias</h2>
<p>Pelo título acima não pense você que vou lhe ensinar a ser carcereiro! Estou me referindo a cadeia de caracteres!</p>
<h3><a title="O_Comando_cut_que_não_é_a_centra" name="O_Comando_cut_que_não_é_a_centra"></a> O Comando cut (que não é a central de trabalhadores) <!--pula duas linhas--></h3>
<p>Primeiro quero te mostrar, de forma eminentemente prática uma instrução simples de usar e muito útil: o comando <code>cut</code>, Esta instrução é usada para cortar um determinado pedaço de um arquivo e tem duas formas distintas de uso</p>
<h4><a title="O_comando_cut_com_a_opção_c" name="O_comando_cut_com_a_opção_c"></a> O comando <code>cut</code> com a opção -c</h4>
<p>Com esta opção, o comando tem a seguinte sintaxe:<br />
<code>cut -c PosIni-PosFim [arquivo]</code></p>
<p>Onde:<br />
<code>PosIni = Posição inicial</code><br />
<code>PosFim = Posição final</code></p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat numeros<br />
<font color="#ffffff">1234567890<br />
0987654321<br />
1234554321<br />
9876556789</font><br />
$ cut -c1-5 numeros<br />
<font color="#ffffff">12345<br />
09876<br />
12345<br />
98765</font><br />
$ cut -c-6 numeros<font color="#ffffff"><br />
123456<br />
098765<br />
123455<br />
987655</font><br />
$ cut -c4- numeros<font color="#ffffff"><br />
4567890<br />
7654321<br />
4554321<br />
6556789</font><br />
$ cut -c1,3,5,7,9 numeros<font color="#ffffff"><br />
13579<br />
08642<br />
13542<br />
97568</font><br />
$ cut -c -3,5,8- numeros<font color="#ffffff"><br />
1235890<br />
0986321<br />
1235321<br />
9875789</font></div>
<p>Como dá para ver, no duro mesmo existem quatro sintaxes distintas: na primeira <code>(-c 1-5)</code>, eu especifiquei uma faixa, na segunda <code>(-c -6)</code>, especifiquei tudo até uma posição, na terceira <code>(-c 4-)</code> de uma determinada posição em diante e na quarta <code>(-c 1,3,5,7,9)</code>, determinadas posições. A última <code>(-c -3,5,8-)</code> foi só para mostrar que podemos misturar tudo.</p>
<h4><a title="O_comando_cut_com_a_opção_f" name="O_comando_cut_com_a_opção_f"></a> O comando <code>cut</code> com a opção -f</h4>
<p>Mas não pense você que acabou por aí! Como você deve ter percebido esta forma de <code>cut</code> é útil para arquivos com campos de tamanho fixo, mas atualmente o que mais existe são arquivos com campos de tamanho variáveis, onde cada campo termina com um delimitador. Vamos dar uma olhada no arquivo <code>musicas</code> que começamos a preparar no nosso papo na última vez que viemos aqui no botequim.</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat musicas<font color="#ffffff"><br />
album 1^Artista1~Musica1:Artista2~Musica2<br />
album 2^Artista3~Musica3:Artista4~Musica4<br />
album 3^Artista5~Musica5:Artista6~Musica5<br />
album 4^Artista7~Musica7:Artista8~Musica8</font></div>
<p>Então, recapitulando, o seu <i>&#8220;leiaute&#8221;</i> é o seguinte:<br />
<code>nome do album^interprete1~nome da musica1:...:interpreten~nome da musican</code></p>
<p>isto é, o nome do álbum será separado por um circunflexo (<code>^</code>) do resto do registro, que é formado por diversos grupos compostos pelo intérprete de cada música do CD e a respectiva música interpretada. Estes grupos são separados entre si por dois-pontos (<code>:</code>) e internamente, o nome do intérprete será separado por um til (<code>~</code>) do nome da música.</p>
<p>Então para pegarmos os dados referentes a todas as segundas músicas do arquivo <code>musicas</code>, devemos fazer:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cut -f2 -d: musicas<font color="#ffffff"><br />
Artista2~Musica2<br />
Artista4~Musica4<br />
Artista6~Musica5<br />
Artista8~Musica8</font></div>
<p>Ou seja, cortamos o segundo campo (<code>-f</code> de <i>field</i> em inglês) delimitado (<code>-d</code>) por dois-pontos (<code>:</code>). Mas, se quisermos somente os intérpretes, devemos fazer:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cut -f2 -d: musicas | cut -f1 -d~<font color="#ffffff"><br />
Artista2<br />
Artista4<br />
Artista6<br />
Artista8</font></div>
<p>Para entender isso, vamos pegar a primeira linha de <code>musicas</code>:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ head -1 musicas<font color="#ffffff"><br />
album 1^Artista1~Musica1:Artista2~Musica2</font></div>
<p>Então observe o que foi feito:</p>
<p>Delimitador do primeiro <code>cut</code> (<code>:</code>)</p>
<p><code><font color="#ff6600">album 1^Artista1~Musica1</font>:<font color="#ff00ff">Artista2~Musica2</font></code></p>
<p>Desta forma, no primeiro <code>cut</code>, o primeiro campo do delimitador (<code>-d</code>) dois-pontos (<code>:</code>) é <font color="#ff6600">album 1^Artista1~Musica1</font> e o segundo, que é o que nos interessa, é <font color="#ff00ff">Artista2~Musica2</font>.</p>
<p>Vamos então ver o que aconteceu no segundo <code>cut</code>:</p>
<p>Novo delimitador (<code>~</code>)</p>
<p><code><font color="#ff6600">Artista2</font>~<font color="#ff00ff">Musica2</font></code></p>
<p>Agora, primeiro campo do delimitador (<code>-d</code>) til (<code>~</code>), que é o que nos interessa, é <font color="#ff6600">Artista2</font> e o segundo é <font color="#ff00ff">Musica2</font>.</p>
<p>Se o raciocínio que fizemos para a primeira linha for aplicado no restante do arquivo, chegaremos à resposta anteriormente dada.</p>
<h3><a title="Se_tem_cut_tem_paste" name="Se_tem_cut_tem_paste"></a> Se tem cut tem paste</h3>
<p>Como já era de se esperar, o comando <code>paste</code>  serve para colar, só que aqui no <i>Shell</i> o que ele cola são arquivos. Só para começar a entendê-lo, vamos fazer assim::</p>
<pre>    paste arq1 arq2</pre>
<p>Desta forma ele mandará para a saída padrão (<code>stdout</code>) cada um dos registros de <code>arq1</code> ao lado dos registros de <code>arq2</code> correspondentes e caso nenhum delimitador seja especificado, ele usará por <i>default</i> o <code>&lt;TAB&gt;</code>.</p>
<p>O paste é um comando pouco usado por sua sintaxe ser pouco conhecida. Vamos brincar com 2 arquivos criados da seguinte forma:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ seq 10 &gt; inteiros<br />
$ seq 2 2 10 &gt; pares</div>
<p>Para ver o conteúdo dos arquivos criados, vamos usar o <code>paste</code> na sua forma careta que mostramos acima:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ paste inteiros pares<font color="#ffffff"><br />
1       2<br />
2       4<br />
3       6<br />
4       8<br />
5       10<br />
6<br />
7<br />
8<br />
9<br />
10</font></div>
<h4><a title="Quem_está_em_pé_deita" name="Quem_está_em_pé_deita"></a> Quem está em pé, deita</h4>
<p>Agora vamos transformar a coluna do <code>pares</code> em linha:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ paste -s pares<font color="#ffffff"><br />
2       4       6       8       10</font></div>
<h4><a title="Usando_separadores" name="Usando_separadores"></a> Usando separadores</h4>
<p>Como já foi dito, o separador <i>default</i> do <code>paste</code> é o <code>&lt;TAB&gt;</code>, mas isso pode ser alterado com a opção <code>-d</code>. Então para calcular a soma do conteúdo de <code>pares</code> primeiramente faríamos:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ paste -s -d&#8217;+&#8217; pares # também poderia ser -sd&#8217;+&#8217;<font color="#ffffff"><br />
2+4+6+8+10</font></div>
<p>e depois passaríamos esta linha para a calculadora (<code>bc</code>) e então ficaria:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ paste -sd&#8217;+&#8217; pares | bc<font color="#ffffff"><br />
30</font></div>
<p>Assim sendo, para calcular o fatorial do número contido em <code>$Num</code>, basta:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ seq $Num | paste -sd&#8217;*&#8217; | bc</div>
<p>Com o comando <code>paste</code> você também pode montar formatações exóticas como esta a seguir:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ ls | paste -s -d&#8217;ttn&#8217;<font color="#ffffff"><br />
arq1    arq2    arq3<br />
arq4    arq5    arq6</font></div>
<p>O que aconteceu foi o seguinte: foi especificado para o comando <code>paste</code> que ele transformaria linhas em colunas (pela opção <code>-s</code>) e que os seus separadores (é&#8230;! Ele aceita mais de um, mas somente um após cada coluna criada pelo comando) seriam uma <code>&lt;TAB&gt;</code>, outra <code>&lt;TAB&gt;</code> e um <code>&lt;ENTER&gt;</code>, gerando desta forma a saída tabulada em 3 colunas.</p>
<p>Agora que você já entendeu isto, veja como fazer a mesma coisa, porém de forma mais fácil e menos bizarra e tosca, usando o mesmo comando mas com a seguinte sintaxe:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ ls | paste &#8211; - -<font color="#ffffff"><br />
arq1    arq2    arq3<br />
arq4    arq5    arq6</font></div>
<p>E isto acontece porque se ao invés de especificarmos os arquivos colocarmos o sinal de menos (<code>-</code>), o comando <code>paste</code> os substitui pela saída ou entrada padrão conforme o caso. No exemplo anterior os dados foram mandados para a saída padrão (<code>stdout</code>), porque o <i>pipe</i> (<code>|</code>) estava desviando a saída do <code>ls</code> para a entrada padrão (<code>stdin</code>) do <code>paste</code>, mas veja o exemplo a seguir:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat arq1<font color="#ffffff"><br />
predisposição<br />
privilegiado<br />
profissional</font><br />
$ cat arq2<font color="#ffffff"><br />
encher<br />
mário<br />
motor</font><br />
$ cut -c-3 arq1 | paste -d &#8220;&#8221; &#8211; arq2<font color="#ffffff"><br />
preencher<br />
primário<br />
promotor</font></div>
<p>Neste caso, o <code>cut</code> devolveu as três primeiras letras de cada registro de <code>arq1</code>, o <code>paste</code> foi montado para não ter separador (<code>-d""</code>) e receber a entrada padrão (desviada pelo <i>pipe</i>) no traço (<code>-</code>) gerando a saída juntamente com <code>arq2</code>.</p>
<h3><a title="O_Comando_tr" name="O_Comando_tr"></a> O Comando tr</h3>
<p>Outro comando muito interessante é o tr que serve para substituir, comprimir ou remover caracteres. Sua sintaxe segue o seguinte padrão:</p>
<pre>    tr [opções] cadeia1 [cadeia2]</pre>
<p>O comando <code>tr</code> copia o texto da entrada padrão (<i>stdin</i>), troca as ocorrência dos caracteres de <code>cadeia1</code> pelo seu correspondente na <code>cadeia2</code> ou troca múltiplas ocorrências dos caracteres de <code>cadeia1</code> por somente um caracter, ou ainda remove caracteres da <code>cadeia1</code>.</p>
<p>As principais <code>opções</code> do comando são:</p>
<table class="twikiTable" border="0" cellpadding="4" cellspacing="1">
<tr>
<th colspan="2" class="twikiFirstCol" align="center" bgcolor="#0000ff"><b><font color="#ffff00">Principais Opções do comando tr</font></b></th>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><b>Opção</b></td>
<td bgcolor="#dddddd"><b>Significado</b></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb">-s</td>
<td bgcolor="#bbbbbb">Comprime n ocorrências de cadeia1 em apenas uma</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd">-d</td>
<td bgcolor="#dddddd">Remove os caracteres de cadeia1</td>
</tr>
</table>
<h4><a title="Trocando_caracteres_com_tr" name="Trocando_caracteres_com_tr"></a><a title="Trocando_caracteres_com_tr_" name="Trocando_caracteres_com_tr_"></a> Trocando caracteres com <code>tr</code></h4>
<p>Primeiro vou te dar um exemplo bem bobo:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo bobo | tr o a<font color="#ffffff"><br />
baba</font></div>
<p>Isto é, troquei todas as ocorrências da letra <code>o</code> pela letra <code>a</code>.</p>
<p>Suponha que em um determinado ponto do meu <i>script</i> eu peça ao operador para teclar <code>s</code> ou <code>n</code> (sim ou não), e guardo sua resposta na variável <code>$Resp</code>. Ora o conteúdo de <code>$Resp</code> pode estar com letra maiúscula ou minúscula, e desta forma eu teria que fazer diversos testes para saber se a resposta dada foi <code>S</code>, <code>s</code>, <code>N</code> ou <code>n</code>. Então o melhor é fazer:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ Resp=$(echo $Resp | tr SN sn)</div>
<p>e após este comando eu teria certeza que o conteúdo de <code>$Resp</code> seria um <code>s</code> ou um <code>n</code>.</p>
<p>Se o meu arquivo <code>ArqEnt</code> está todo escrito com letras maiúsculas e desejo passá-las para minúsculas eu faço:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ tr A-Z a-z &lt; ArqEnt &gt; /tmp/$$<br />
$ mv -f /tmp/$$ ArqEnt</div>
<p>Note que neste caso usei a notação <code>A-Z</code> para não escrever <code>ABCD...YZ</code>. Outro tipo de notação que pode ser usada são as <i>escape sequences</i> (prefiro escrever no bom e velho português, mas nesse caso como eu traduziria? Seqüências de escape? Meio sem sentido, né? Mas vá lá&#8230;) que também são reconhecidas por outros comandos e também na linguagem C, e cujo significado você verá a seguir:</p>
<table class="twikiTable" border="0" cellpadding="4" cellspacing="1">
<tr>
<th colspan="3" class="twikiFirstCol" align="center" bgcolor="#0000ff"><b><font color="#ffff00">Escape Sequences</font></b></th>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><b>Seqüência</b></td>
<td bgcolor="#dddddd"><b>Significado</b></td>
<td bgcolor="#dddddd"><b>Octal</b></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb">t</td>
<td bgcolor="#bbbbbb">Tabulação</td>
<td align="center" bgcolor="#bbbbbb">11</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd">n</td>
<td bgcolor="#dddddd">Nova linha</td>
<td align="center" bgcolor="#dddddd">12</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb">v</td>
<td bgcolor="#bbbbbb">Tabulação Vertical</td>
<td align="center" bgcolor="#bbbbbb">13</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd">f</td>
<td bgcolor="#dddddd">Nova Página</td>
<td align="center" bgcolor="#dddddd">14</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb">r</td>
<td bgcolor="#bbbbbb">Início da linha &lt;^M&gt;</td>
<td align="center" bgcolor="#bbbbbb">15</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd">\</td>
<td bgcolor="#dddddd">Uma barra invertida</td>
<td align="center" bgcolor="#dddddd">134</td>
</tr>
</table>
<h4><a title="Removendo_caracteres_com_tr" name="Removendo_caracteres_com_tr"></a><a title="Removendo_caracteres_com_tr_" name="Removendo_caracteres_com_tr_"></a> Removendo caracteres com <code>tr</code></h4>
<p>Então deixa eu te contar um &#8220;causo&#8221;: um aluno que estava danado comigo, resolveu complicar a minha vida e em um exercício prático valendo nota que passei para ser feito no computador, me entregou o <i>script</i> com todos os comandos separados por ponto-e-vírgula (lembra que eu disse que o ponto-e-vírgula servia para separar diversos comandos em uma mesma linha?).</p>
<p>Vou dar um exemplo simplificado e idiota de uma &#8220;tripa&#8221; assim:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat confuso<font color="#ffffff"><br />
echo leia Programação Shell Linux do Julio Cezar Neves &gt; livro;cat livro;pwd;ls;rm -f lixo 2&gt;/dev/null;cd ~</font></div>
<p>Eu executava o programa e ele funcionava:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ confuso<font color="#ffffff"><br />
leia Programação Shell Linux do Julio Cezar Neves<br />
/home/jneves/LM<br />
confuso  livro  musexc  musicas  musinc  muslist  numeros</font></div>
<p>Mas nota de prova é coisa séria (e nota de dólar é mais ainda <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> ) então, para entender o que o aluno havia feito, o chamei e em sua frente executei o seguinte comando:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ tr &#8220;;&#8221; &#8220;n&#8221; &lt; confuso<font color="#ffffff"><br />
echo leia Programação Shell Linux do Julio Cezar Neves<br />
pwd<br />
ls<br />
rm -f lixo 2&gt;/dev/null</font><br />
cd ~</div>
<p>O cara ficou muito desapontado, porque em 2 ou 3 segundos eu desfiz a gozação que ele perdera horas para fazer.<br />
Mas preste atenção! Se eu estivesse em uma máquina com Unix, eu teria feito:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ tr &#8220;;&#8221; &#8220;12&#8243; &lt; confuso</div>
<h4><a title="Xpremendo_com_tr" name="Xpremendo_com_tr"></a><a title="Xpremendo_com_tr_" name="Xpremendo_com_tr_"></a> Xpremendo com <code>tr</code></h4>
<p>Agora veja a diferença entre os dois comandos <code>date</code>: o que fiz hoje e outro que foi executado há duas semanas:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ date      # Hoje<font color="#ffffff"><br />
Sun Sep 19 14:59:54  2004</font><br />
$ date      # Há duas semanas<font color="#ffffff"><br />
Sun Sep  5 10:12:33  2004</font></div>
<p>Para pegar a hora eu deveria fazer:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ date | cut -f 4 -d &#8216; &#8216;<font color="#ffffff"><br />
14:59:54</font></div>
<p>Mas duas semanas antes ocorreria o seguinte:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ date | cut -f 4 -d &#8216; &#8216;<font color="#ffffff"><br />
5</font></div>
<p>Mas observe porque:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ date      # Há duas semanas<font color="#ffffff"><br />
Sun Sep  5 10:12:33  2004</font></div>
<p>Como você pode notar, existem 2 caracteres em branco antes do <code>5</code> (dia), o que estraga tudo porque o terceiro pedaço está vazio e o quarto é o dia (<code>5</code>). Então o ideal seria comprimir os espaços em brancos sucessivos em somente um espaço para poder tratar as duas cadeias resultantes do comando <code>date</code> da mesma forma, e isso se faz assim:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ date | tr -s &#8221; &#8220;a<font color="#ffffff"><br />
Sun Sep 5 10:12:33 2004</font></div>
<p>Como você pode ver não existem mais os dois espaços, então agora eu poderia cortar:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ date | tr -s &#8221; &#8221; | cut -f 4 -d &#8221; &#8220;<font color="#ffffff"><br />
10:12:33</font></div>
<p>Olha só como o <i>Shell</i> já está quebrando o galho. Veja este arquivo que foi baixado de uma máquina com aquele sistema operacional que pega vírus:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat -ve ArqDoDOS.txt<font color="#ffffff"><br />
Este arquivo^M$<br />
foi gerado pelo^M$<br />
DOS/Rwin e foi^M$<br />
baixado por um^M$<br />
ftp mal feito.^M$</font></div>
<p>E agora eu quero te dar duas dicas:</p>
<div style="border:1px dashed red;min-height:121px;background-color:#ffffcc;margin:1em;padding:1em;"><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" style="float:left;padding:0 8px 0 0;" alt="Pinguim com placa de dica" align="left" /> <b>Dica #1</b> &#8211; A opção <code>-v</code> do <code>cat</code> mostra os caracteres de controle invisíveis, com a notação <code>^L</code>, onde <code>^</code> é a tecla control e <code>L</code> é a respectiva letra. A opção <code>-e</code> mostra o final da linha como um cifrão (<code>$</code>).</div>
<div style="border:1px dashed red;min-height:121px;background-color:#ffffcc;margin:1em;padding:1em;"><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" style="float:left;padding:0 8px 0 0;" alt="Pinguim com placa de dica" align="left" /> <b>Dica #2</b> &#8211; Isto ocorre porque no formato DOS (ou rwin), o fim dos registros é formado por um <i>carriage-return</i> (<code>r</code>) e um <i>line-feed</i> (<code>n</code>). No Linux porém o final do registro tem somente o <i>line-feed</i>.</div>
<p>Vamos então limpar este arquivo.</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ tr -d &#8216;r&#8217; &lt; ArqDoDOS.txt &gt; /tmp/$$<br />
$ mv -f /tmp/$$ ArqDoDOS.txt</div>
<p>Agora vamos ver o que aconteceu:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat -ve ArqDoDOS.txt<font color="#ffffff"><br />
Este arquivo$<br />
foi gerado pelo$<br />
DOS/Rwin e foi$<br />
baixado por um$<br />
ftp mal feito.$</font></div>
<p>Bem a opção <code>-d</code> do <code>tr</code> remove o caractere especificado de todo o arquivo. Desta forma eu removi os caracteres indesejados salvando em um arquivo de trabalho e posteriormente renomeei-o para a sua designação original.<br />
Obs: No Unix eu deveria fazer:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ tr -d &#8217;15&#8242; &lt; ArqDoDOS.txt &gt; /tmp/$$</div>
<div style="border:1px dashed red;min-height:105px;background-color:#ffffcc;margin:1em;padding:1em;"><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_atencao.gif" style="float:left;padding:0 8px 0 0;" alt="Pinguim com placa de atenção" /> Isto aconteceu porque o <code>ftp</code> foi feito do modo binário (ou <code>image</code>), isto é, sem a interpretação do texto. Se antes da transmissão do arquivo tivesse sido estipulada a opção <code>ascii</code> do <code>ftp</code>, isto não teria ocorrido.</div>
<p>- Olha, depois desta dica tô começando a gostar deste tal de <i>Shell</i>, mas ainda tem muita coisa que não consigo fazer.</p>
<p>- Pois é, ainda não te falei quase nada sobre programação em <i>Shell</i>, ainda tem muita coisa para aprender, mas com o que aprendeu, já dá para resolver muitos problemas, desde que você adquira o “modo <i>Shell</i> de pensar”. Você seria capaz de fazer um <i>script</i> para me dizer quais são as pessoas que estão “logadas” há mais de um dia no seu servidor?</p>
<p>- Claro que não! Para isso seria necessário eu conhecer os comandos condicionais que você ainda não me explicou como funcionam.</p>
<p>- Deixa eu tentar mudar um pouco a sua lógica e trazê-la para o “modo <i>Shell</i> de pensar”, mas antes é melhor tomarmos um chope&#8230; Ô Chico, traz mais dois&#8230;</p>
<p>- Agora que já molhei a palavra, vamos resolver o problema que te propus. Repare como funciona o comando who:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ who<font color="#ffffff"><br />
jneves   pts/1        Sep 18 13:40<br />
rtorres  pts/0        Sep 20 07:01<br />
rlegaria pts/1        Sep 20 08:19<br />
lcarlos  pts/3        Sep 20 10:01</font></div>
<p>E veja também o <code>date</code>:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ date<font color="#ffffff"><br />
Mon Sep 20 10:47:19 BRT 2004</font></div>
<p>Repare que o mês e o dia estão no mesmo formato em ambos os comandos.</p>
<div style="border:1px dashed red;min-height:121px;background-color:#ffffcc;margin:1em;padding:1em;"><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" style="float:left;padding:0 8px 0 0;" alt="Pinguim com placa de dica" align="left" /> Algumas vezes um comando tem a saída em português e o outro em inglês. Quando isso ocorrer, você pode usar o seguinte artifício:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ date<font color="#ffffff"><br />
Mon Sep 20 10:47:19 BRT 2004</font><br />
$ LANG=pt_BR date<font color="#ffffff"><br />
Seg Set 20 10:47:19 BRT 2004</font></div>
<p>Desta forma passando a saída do comando <code>date</code> para português.</div>
<p>Ora, se em algum registro do <code>who</code> eu não encontrar a data de hoje, é sinal que o cara está &#8220;logado&#8221; há mais de um dia, já que ele não pode ter se &#8220;logado&#8221; amanhã&#8230; Então vamos guardar o pedaço que importa da data de hoje para procurá-la na saída do <code>who</code>:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ Data=$(date | cut -c 5-10)</div>
<p>Eu usei a construção <code>$(...)</code>, para priorizar a execução dos comandos antes de atribuir a sua saída à variável <code>$Data</code>. Vamos ver se funcionou:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo $Data<font color="#ffffff"><br />
Sep 20</font></div>
<p>Beleza! Agora, o que temos que fazer é procurar no comando <code>who</code> os registros que não possuem esta data.</p>
<p>- Ah! Eu acho que estou entendendo! Você falou em procurar e me ocorreu o comando <code>grep</code>, estou certo?</p>
<p>- Certíssimo! Só que eu tenho que usar o <code>grep</code> com aquela opção que ele só lista os registros nos quais ele <b>não</b> encontrou a cadeia. Você se lembra que opção é essa?</p>
<p>- Claro, é a opção <code>-v</code>&#8230;</p>
<p>- Isso! Tá ficando bão! Então vamos ver:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ who | grep -v &#8220;$Data&#8221;<font color="#ffffff"><br />
jneves   pts/1        Sep 18 13:40</font></div>
<p>- E se eu quisesse mais um pouco de perfumaria eu faria assim:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ who | grep -v &#8220;$Data&#8221; | cut -f1 -d &#8216; &#8216;<font color="#ffffff"><br />
jneves</font></div>
<p>- Viu? Não foi necessário usar nenhum comando condicional, até porque o nosso mais usado comando condicional, o famoso <code>if</code>, não testa condição, mas sim instruções, como veremos agora.</p>
<h2><a title="Comandos_Condicionais" name="Comandos_Condicionais"></a> Comandos Condicionais</h2>
<p>Veja as linhas de comando a seguir:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ ls musicas<font color="#ffffff"><br />
musicas</font><br />
$ echo $?<font color="#ffffff"><br />
0</font><br />
$ ls ArqInexistente<font color="#ffffff"><br />
ls: ArqInexistente: No such file or directory</font><br />
$ echo $?<font color="#ffffff"><br />
1</font><br />
$ who | grep jneves<font color="#ffffff"><br />
jneves   pts/1        Sep 18 13:40 (10.2.4.144)</font><br />
$ echo $?<font color="#ffffff"><br />
0</font><br />
$ who | grep juliana<font color="#ffffff"><br />
$ echo $?</font><br />
1</div>
<p>- O que é esse <code>$?</code> faz aí? Começando por cifrão (<code>$</code>) parece ser uma variável, certo?</p>
<p>- Sim é uma variável que contém o código de retorno da última instrução executada. Posso te garantir que se esta instrução foi bem sucedida, $? terá o valor zero, caso contrário seu valor será diferente de zero.</p>
<h3><a title="O_Comando_if" name="O_Comando_if"></a> O Comando if</h3>
<p>O que o nosso comando condicional <code>if</code> faz é testar a variável <code>$?</code>. Então vamos ver a sua sintaxe:</p>
<pre>    if cmd
    then
        cmd1
        cmd2
        cmdn
    else
        cmd3
        cmd4
        cmdm
    fi</pre>
<p>ou seja: caso comando <code>cmd</code> tenha sido executado com sucesso, os comandos do bloco do <code>then</code> (<code>cmd1</code>, <code>cmd2</code> e <code>cmdn</code>) serão executados, caso contrário, os comandos executados serão os do bloco opcional do <code>else</code> (<code>cmd3</code>, <code>cmd4</code> e <code>cmdm</code>), terminando com um <code>fi</code>.</p>
<p>Vamos ver na prática como isso funciona usando um <i>scriptizinho</i> que serve para incluir usuários no <code>/etc/passwd</code>:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat incusu<font color="#ffffff"><br />
#!/bin/bash<br />
# Versão 1<br />
if  grep ^$1 /etc/passwd<br />
then<br />
echo Usuario &#8216;$1&#8242; já existe<br />
else<br />
if  useradd $1<br />
then<br />
echo Usuário &#8216;$1&#8242; incluído em /etc/passwd<br />
else<br />
echo &#8220;Problemas no cadastramento. Você é root?&#8221;<br />
fi<br />
fi</font></div>
<p>Repare que o <code>if</code> está testando direto o comando <code>grep</code> e esta é a sua finalidade. Caso o <code>if</code> seja bem sucedido, ou seja, o usuário (cujo nome está em <code>$1</code>) foi encontrado em <code>/etc/passwd</code>, os comandos do bloco do <code>then</code> serão executados (neste exemplo é somente o <code>echo</code>) e caso contrário, as instruções do bloco do <code>else</code> é que serão executadas, quando um novo <code>if</code> testa se o comando <code>useradd</code> foi executado a contento, criando o registro do usuário em <code>/etc/passwd</code>, ou não quando dará a mensagem de erro.<br />
Vejamos sua execução, primeiramente passando um usuário já cadastrado:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ incusu jneves<font color="#ffffff"><br />
jneves:x:54002:1001:Julio Neves:/home/jneves:/bin/bash<br />
Usuario &#8216;jneves&#8217; ja existe</font></div>
<p>Como já vimos diversas vezes, mas é sempre bom insistir no tema para que você já fique precavido, no exemplo dado surgiu uma linha indesejada, ela é a saída do comando <code>grep</code>. Para evitar que isso aconteça, devemos desviar a saída desta instrução para <code>/dev/null</code>, ficando assim:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat incusu<font color="#ffffff"><br />
#!/bin/bash<br />
# Versão 2<br />
if  grep ^$1 /etc/passwd &gt; /dev/null     # ou: if grep -q ^$1 /etc/passwd<br />
then<br />
echo Usuario &#8216;$1&#8242; já existe<br />
else<br />
if  useradd $1<br />
then<br />
echo Usuário &#8216;$1&#8242; incluído em /etc/passwd<br />
else<br />
echo &#8220;Problemas no cadastramento. Você é root?&#8221;<br />
fi<br />
fi</font></div>
<p>Agora vamos testá-lo como usuário normal (não <i>root</i>):</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ incusu ZeNinguem<font color="#ffffff"><br />
./incusu[6]: useradd:  not found<br />
Problemas no cadastramento. Você é root?</font></div>
<p>Epa, aquele erro não era para acontecer! Para evitar que isso aconteça devemos mandar também a saída de erro (<i>strerr</i>, lembra?) do <code>useradd</code> para <code>/dev/null</code>, ficando na versão final assim:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat incusu<font color="#ffffff"><br />
#!/bin/bash<br />
# Versão 3<br />
if  grep ^$1 /etc/passwd &gt; /dev/null<br />
then<br />
echo Usuario &#8216;$1&#8242; já existe<br />
else<br />
if  useradd $1 2&gt; /dev/null<br />
then<br />
echo Usuário &#8216;$1&#8242; incluído em /etc/passwd<br />
else<br />
echo &#8220;Problemas no cadastramento. Você é root?&#8221;<br />
fi<br />
fi</font></div>
<p>Depois destas alterações e de fazer um <code>su –</code> (me tornar <i>root</i>) vejamos o seu comportamento:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ incusu botelho<font color="#ffffff"><br />
Usuário &#8216;botelho&#8217; incluido em /etc/passwd</font></div>
<p>E novamente:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ incusu botelho<font color="#ffffff"><br />
Usuário &#8216;botelho&#8217; já existe</font></div>
<p>Lembra que eu falei que ao longo dos nossos papos e chopes os nossos programas iriam se aprimorando? Então vejamos agora como poderíamos melhorar o nosso programa para incluir músicas:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat musinc<font color="#ffffff"><br />
#!/bin/bash<br />
# Cadastra CDs (versao 3)<br />
#<br />
if  grep &#8220;^$1$&#8221; musicas &gt; /dev/null<br />
then<br />
echo Este álbum já está cadastrado<br />
else<br />
echo $1 &gt;&gt; musicas<br />
sort musicas -o musicas<br />
fi</font></div>
<p>Como você viu, é uma pequena evolução da versão anterior, assim, antes de incluir um registro (que pela versão anterior poderia ser duplicado), testamos se o registro começava (<code>^</code>) e terminava (<code>$</code>) igual ao parâmetro passado (<code>$1</code>). O uso do circunflexo (<code>^</code>) no início da cadeia e cifrão (<code>$</code>) no fim, são para testar se o parâmetro passado (o álbum e seus dados) são exatamente iguais a algum registro anteriormente cadastrado e não somente igual a um pedaço de algum dos registros.<br />
Vamos executá-lo passando um álbum já cadastrado:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ musinc &#8220;album 4^Artista7~Musica7:Artista8~Musica8&#8243;<font color="#ffffff"><br />
Este álbum já está cadastrado</font></div>
<p>E agora um não cadastrado:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ musinc &#8220;album 5^Artista9~Musica9:Artista10~Musica10&#8243;<br />
$ cat musicas<font color="#ffffff"><br />
album 1^Artista1~Musica1:Artista2~Musica2<br />
album 2^Artista3~Musica3:Artista4~Musica4<br />
album 3^Artista5~Musica5:Artista6~Musica5<br />
album 4^Artista7~Musica7:Artista8~Musica8<br />
album 5^Artista9~Musica9:Artista10~Musica10</font></div>
<p>- Como você viu, o programa melhorou um pouquinho, mas ainda não está pronto. À medida que eu for te ensinando a programar em <i>shell</i>, nossa CDteca irá ficando cada vez melhor.</p>
<p>- Entendi tudo que você me explicou, mas ainda não sei como fazer um <code>if</code> para testar condições, ou seja o uso normal do comando.</p>
<p>- Cara, para isso existe o comando <code>test</code>, ele é que testa condições. O comando <code>if</code> testa o comando <code>test</code>. 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 próxima vez te explico direitinho o uso do <code>test</code> e de diversas outras sintaxes do <code>if</code>.</p>
<p>- Falou! Acho bom mesmo porque eu também já tô ficando zonzo e assim tenho tempo para praticar esse monte de coisas que você me falou hoje.</p>
<p>- Para fixar o que você aprendeu, tente fazer um <i>scriptizinho</i> para informar se um determinado usuário, que será passado como parâmetro esta logado (arghh!) ou não.</p>
<p>- Aê Chico, mais dois chopes por favor&#8230;</p>
<p>Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em <i>Shell</i> que mande um e-mail para a nossa <a href="mailto:treinamentos@festivalsoftwarelivre.org?Subject=Curso%20de%20Shell%20com%20Julio%20Neves">gerencia de treinamento</a> para informar-se.</p>
<p>Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para <a href="mailto:julioneves@openoffice.org?Subject=D%C3%BAvidas%20Papo%20de%20Botequim">mim</a>.</p>
<p>Valeu!</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/jneves.wordpress.com/15/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/jneves.wordpress.com/15/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jneves.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jneves.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jneves.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jneves.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jneves.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jneves.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jneves.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jneves.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jneves.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jneves.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jneves.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jneves.wordpress.com/15/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jneves.wordpress.com/15/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jneves.wordpress.com/15/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=15&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-3/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/53f0649d2d6a9b19b90abd0575ee5c7c?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">jneves</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" medium="image">
			<media:title type="html">Pinguim com placa de dica</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" medium="image">
			<media:title type="html">Pinguim com placa de dica</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_atencao.gif" medium="image">
			<media:title type="html">Pinguim com placa de atenção</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" medium="image">
			<media:title type="html">Pinguim com placa de dica</media:title>
		</media:content>
	</item>
		<item>
		<title>Papo de Botequim &#8211; Parte 4</title>
		<link>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-4/</link>
		<comments>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-4/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 16:30:22 +0000</pubDate>
		<dc:creator>jneves</dc:creator>
				<category><![CDATA[Shell]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[case]]></category>
		<category><![CDATA[cd]]></category>
		<category><![CDATA[do]]></category>
		<category><![CDATA[done]]></category>
		<category><![CDATA[else]]></category>
		<category><![CDATA[esac]]></category>
		<category><![CDATA[fi]]></category>
		<category><![CDATA[if]]></category>
		<category><![CDATA[mkdir]]></category>
		<category><![CDATA[test]]></category>
		<category><![CDATA[then]]></category>
		<category><![CDATA[{]]></category>
		<category><![CDATA[|]]></category>
		<category><![CDATA[||]]></category>
		<category><![CDATA[}]]></category>

		<guid isPermaLink="false">http://jneves.wordpress.com/?p=14</guid>
		<description><![CDATA[O Comando test Querida, Encolheram o Comando Condicional E tome de test Acaso Casa com case - E aí cara, tentou fazer o exercício que te pedi para revigorar as idéias? - Claro, que sim! Em programação, se você não treinar, não aprende. Você me pediu para fazer um scriptizinho para informar se um determinado [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=14&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div class="twikiToc">
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo004#O_Comando_test"> O Comando test</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo004#Querida_Encolheram_o_Comando_Con">Querida, Encolheram o Comando Condicional</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo004#E_tome_de_test"> E tome de test</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo004#Acaso_Casa_com_case">Acaso Casa com case</a></li>
</ul>
</div>
<p>- E aí cara, tentou fazer o exercício que te pedi para revigorar as idéias?</p>
<p>- Claro, que sim! Em programação, se você não treinar, não aprende. Você me pediu para fazer um <i>scriptizinho</i> para informar se um determinado usuário, que será passado como parâmetro esta logado (arghh!) ou não. Eu fiz o seguinte:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat logado<font color="#ffffff"><br />
#!/bin/bash<br />
# Pesquisa se uma pessoa está logada ou não<br />
if who | grep $1<br />
then<br />
echo $1 está logado<br />
else<br />
echo $1 não se encontra no pedaço<br />
fi</font></div>
<p>- Calma rapaz! Já vi que você chegou cheio de tesão, primeiro vamos pedir os nossos chopes de praxe e depois vamos ao <i>Shell</i>. Chico traz dois chopes, um sem colarinho!</p>
<p>- Agora que já molhamos os nossos bicos, vamos dar uma olhadinha na execução do seu bacalho:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ logado jneves<font color="#ffffff"><br />
jneves   pts/0        Oct 18 12:02 (10.2.4.144)<br />
jneves está logado</font></div>
<p>Realmente funcionou. Passei o meu <i>login</i> como parâmetro e ele disse que eu estava logado, porém ele mandou uma linha que eu não pedi. Esta linha é a saída do comando <code>who</code>, e para evitar que isso aconteça é só mandá-la para o buraco negro que a esta altura você já sabe que é o <code>/dev/null</code>. Vejamos então como ficaria:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat logado<font color="#ffffff"><br />
#!/bin/bash<br />
# Pesquisa se uma pessoa está logada ou não (versão 2)<br />
if who | grep $1 &gt; /dev/null<br />
then<br />
echo $1 está logado<br />
else<br />
echo $1 não se encontra no pedaço<br />
fi</font></div>
<p>Agora vamos aos testes:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ logado jneves<font color="#ffffff"><br />
jneves está logado<br />
$ logado chico<br />
chico não se encontra no pedaço</font></div>
<div style="border:1px dashed red;min-height:105px;background-color:#ffffcc;margin:1em;padding:1em;"><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_atencao.gif" style="float:left;padding:0 8px 0 0;" alt="Pinguim com placa de atenção" /> Ah, agora sim! Lembre-se desta pegadinha, a maior parte dos comandos tem uma saída padrão e uma saída de erros (o <code>grep</code> é uma das poucos exceções, já que não dá mensagem de erro quando não acha uma cadeia) e é necessário estarmos atentos para redirecioná-las para o buraco negro quando necessário.</div>
<p>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á estávamos de goela seca falando sobre o if, você me perguntou como se testa condições. Vejamos então o</p>
<h2><a title="O_Comando_test" name="O_Comando_test"></a> O Comando test</h2>
<p>Bem, todos estamos acostumados a usar o <code>if</code> testando condições, e estas são sempre, maior, menor, maior ou igual, menor ou igual, igual e diferente. Bem, em <i>Shell</i> para testar condições, usamos o comando <code>test</code>, só que ele é muito mais poderoso que o que estamos habituados. Primeiramente vou te mostrar as principais opções (existem muitas outras) para testarmos arquivos em disco:</p>
<table class="twikiTable" border="0" cellpadding="4" cellspacing="1">
<tr>
<th colspan="2" class="twikiFirstCol" align="center" bgcolor="#0000ff"><b><font color="#ffff00">Opções do Comando test para arquivos</font></b></th>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><b>Opção</b></td>
<td bgcolor="#dddddd"><b>Verdadeiro se:</b></td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#bbbbbb"><code>-e arq</code></td>
<td bgcolor="#bbbbbb"><code>arq</code> existe</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><code>-s arq</code></td>
<td bgcolor="#dddddd"><code>arq</code> existe e tem tamanho maior que zero</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#bbbbbb"><code>-f arq</code></td>
<td bgcolor="#bbbbbb"><code>arq</code> existe e é um arquivo regular</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><code>-d arq</code></td>
<td bgcolor="#dddddd"><code>arq</code> existe e é um diretório;</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#bbbbbb"><code>-r arq</code></td>
<td bgcolor="#bbbbbb"><code>arq</code> existe e com direito de leitura</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><code>-w arq</code></td>
<td bgcolor="#dddddd"><code>arq</code> existe e com direito de escrita</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#bbbbbb"><code>-x arq</code></td>
<td bgcolor="#bbbbbb"><code>arq</code> existe e com direito de execução</td>
</tr>
</table>
<p>Veja agora as principais opções para teste de cadeias de caracteres:</p>
<table class="twikiTable" border="0" cellpadding="4" cellspacing="1">
<tr>
<th colspan="2" class="twikiFirstCol" align="center" bgcolor="#0000ff"><b><font color="#ffff00">Opções do comando test para cadeias de caracteres</font></b></th>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><b>Opção</b></td>
<td bgcolor="#dddddd"><b>Verdadeiro se:</b></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>-z cadeia</code></td>
<td bgcolor="#bbbbbb">Tamanho de <code>cadeia</code> é zero</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><code>-n cadeia</code></td>
<td bgcolor="#dddddd">Tamanho de <code>cadeia</code> é maior que zero</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>cadeia</code></td>
<td bgcolor="#bbbbbb">A cadeia <code>cadeia</code> tem tamanho maior que zero</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><code>c1 = c2</code></td>
<td bgcolor="#dddddd">Cadeia <code>c1</code> e <code>c2</code> são idênticas</td>
</tr>
</table>
<p>E pensa que acabou? Engano seu! Agora é que vem o que você está mais acostumado, ou seja as famosas comparações com numéricos. Veja a tabela:</p>
<table class="twikiTable" border="0" cellpadding="4" cellspacing="1">
<tr>
<th colspan="3" class="twikiFirstCol" align="center" bgcolor="#0000ff"><b><font color="#ffff00">Opções do comando test para números</font></b></th>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><b>Opção</b></td>
<td bgcolor="#dddddd"><b>Verdadeiro se:</b></td>
<td bgcolor="#dddddd"><b>Significado</b></td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#bbbbbb"><code>n1 -eq n2</code></td>
<td bgcolor="#bbbbbb"><code>n1</code> e <code>n2</code> são iguais</td>
<td bgcolor="#bbbbbb">equal</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><code>n1 -ne n2</code></td>
<td bgcolor="#dddddd"><code>n1</code> e <code>n2</code> não são iguais</td>
<td bgcolor="#dddddd">not equal</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#bbbbbb"><code>n1 -gt n2</code></td>
<td bgcolor="#bbbbbb"><code>n1</code> é maior que <code>n2</code></td>
<td bgcolor="#bbbbbb">greater than</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><code>n1 -ge n2</code></td>
<td bgcolor="#dddddd"><code>n1</code> é maior ou igual a <code>n2</code></td>
<td bgcolor="#dddddd">greater or equal</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#bbbbbb"><code>n1 -lt n2</code></td>
<td bgcolor="#bbbbbb"><code>n1</code> é menor que <code>n2</code></td>
<td bgcolor="#bbbbbb">less than</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><code>n1 -le n2</code></td>
<td bgcolor="#dddddd"><code>n1</code> é menor ou igual a <code>n2</code></td>
<td bgcolor="#dddddd">less or equal</td>
</tr>
</table>
<p>Além de tudo, some-se a estas opções as seguintes facilidades:</p>
<table class="twikiTable" border="0" cellpadding="4" cellspacing="1">
<tr>
<th colspan="2" class="twikiFirstCol" align="center" bgcolor="#0000ff"><b><font color="#ffff00">Operadores</font></b></th>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><b>Operador</b></td>
<td align="center" bgcolor="#dddddd"><b>Finalidade</b></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb">Parênteses <code>( )</code></td>
<td align="center" bgcolor="#bbbbbb">Agrupar</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd">Exclamação <code>!</code></td>
<td align="center" bgcolor="#dddddd">Negar</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>-a</code></td>
<td align="center" bgcolor="#bbbbbb"><code>E</code> lógico</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><code>-o</code></td>
<td align="center" bgcolor="#dddddd"><code>OU</code> lógico</td>
</tr>
</table>
<p>Ufa! Como você viu tem coisa prá chuchu, e como eu te disse no início, o nosso <code>if</code> é muito mais poderoso que o dos outros. Vamos ver em uns exemplos como isso tudo funciona, primeiramente testaremos a existência de um diretório:</p>
<p>Exemplos:</p>
<pre>    if  test -d lmb
    then
        cd lmb
    else
        mkdir lmb
        cd lmb
    fi</pre>
<p>No exemplo, testei se existia um diretório <code>lmb</code> definido, caso negativo (<code>else</code>), ele seria criado. Já sei, você vai criticar a minha lógica dizendo que o <i>script</i> não está otimizado. Eu sei, mas queria que você o entendesse assim, para então poder usar o ponto-de-espantação (<code>!</code>) como um negador do <code>test</code>. Veja só:</p>
<pre>    if  test ! -d lmb
    then
        mkdir lmb
    fi
    cd lmb</pre>
<p>Desta forma o diretório <code>lmb</code> seria criado somente se ele ainda não existisse, e esta negativa deve-se ao ponto-de-exclamação (<code>!</code>) precedendo a opção <code>-d</code>. Ao fim da execução deste fragmento de <i>script</i>, o programa estaria com certeza dentro do diretório <code>lmb</code>.</p>
<p>Vamos ver dois exemplos para entender a diferença comparação entre números e entre cadeias.</p>
<pre>    cad1=1
    cad2=01
    if  test $cad1 = $cad2
    then
        echo As variáveis são iguais.
    else
        echo As variáveis são diferentes.
    fi</pre>
<p>Executando o fragmento de programa acima vem:</p>
<p><code>As variáveis são diferentes.</code></p>
<p>Vamos agora alterá-lo um pouco para que a comparação seja numérica:</p>
<pre>    cad1=1
    cad2=01
    if  test $cad1 -eq $cad2
    then
        echo As variáveis são iguais.
    else
        echo As variáveis são diferentes.
    fi</pre>
<p>E vamos executá-lo novamente:</p>
<p><code>As variáveis são iguais.</code></p>
<p>Como você viu nas duas execuções obtive resultados diferentes porque a cadeia <code>01</code> é realmente diferente da cadeia <code>1</code>, porém, a coisa muda quando as variáveis são testadas numericamente, já que o número <code>1</code> é igual ao número <code>01</code>.</p>
<p>Exemplos:</p>
<p>Para mostrar o uso dos conectores <code>-o</code> (<code>OU</code>) e <code>-a</code> (<code>E</code>), veja um exemplo animal feito direto no <i>prompt</i> (me desculpem os zoólogos, mas eu não entendendo nada de reino, filo, classe, ordem, família, gênero e espécie, desta forma o que estou chamando de família ou de gênero tem grande chance de estar incorreto):</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ Familia=felinae<br />
$ Genero=gato<br />
$ if  test $Familia = canidea -a $Genero = lobo -o $Familia = felina -a $Genero = leão<br />
&gt; then<br />
&gt;     echo Cuidado<br />
&gt; else<br />
&gt;     echo Pode passar a mão<br />
&gt; fi<font color="#ffffff"><br />
Pode passar a mão</font></div>
<p>Neste exemplo caso o animal fosse da família canídea <code>E</code> (<code>-a</code>) do gênero lobo, <code>OU</code> (<code>-o</code>) da familia felina <code>E</code> (<code>-a</code>) do gênero leão, seria dado um alerta, caso contrário a mensagem seria de incentivo.</p>
<div style="border:1px dashed red;min-height:121px;background-color:#ffffcc;margin:1em;padding:1em;"><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" style="float:left;padding:0 8px 0 0;" alt="Pinguim com placa de dica" align="left" /> Os sinais de maior (<code>&gt;</code>) no início das linhas internas ao <code>if</code> são os <i>prompts</i> de continuação (que estão definidos na variável <code>$PS2</code>) e quando o <i>Shell</i> identifica que um comando continuará na linha seguinte, automaticamente ele o coloca até que o comando seja encerrado.</div>
<p>Vamos mudar o exemplo para ver se continua funcionando:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ Familia=felino<br />
$ Genero=gato<br />
$ if  test $Familia = felino -o $Familia = canideo -a $Genero = onça -o $Genero = lobo<br />
&gt; then<br />
&gt;     echo Cuidado<br />
&gt; else<br />
&gt;     echo Pode passar a mão<br />
&gt; fi<font color="#ffffff"><br />
Cuidado</font></div>
<p>Obviamente a operação redundou em erro, isto foi porque a opção <code>-a</code> tem precedência sobre a <code>-o</code>, e desta forma o que primeiro foi avaliado foi a expressão:</p>
<p><code>$Familia = canideo -a $Genero = onça</code></p>
<p>Que foi avaliada como falsa, retornando o seguinte:</p>
<p><code>$Familia = felino -o FALSO -o $Genero = lobo</code></p>
<p>Que resolvida vem:</p>
<p><code>VERDADEIRO -o FALSO -o FALSO</code></p>
<p>Como agora todos conectores são <code>-o</code>, e para que uma série de expressões conectadas entre si por diversos <code>OU</code> lógicos seja verdadeira, basta que uma delas seja, a expressão final resultou como <code>VERDADEIRO</code> e o <code>then</code> foi executado de forma errada. Para que isso volte a funcionar façamos o seguinte:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ if  test ($Familia = felino -o $Familia = canideo) -a ($Genero = onça -o $Genero = lobo)<br />
&gt; then<br />
&gt;     echo Cuidado<br />
&gt; else<br />
&gt;     echo Pode passar a mão<br />
&gt; fi<font color="#ffffff"><br />
Pode passar a mão</font></div>
<p>Desta forma, com o uso dos parênteses agrupamos as expressões com o conector <code>-o</code>, priorizando as suas execuções e resultando:</p>
<p><code>VERDADEIRO -a FALSO</code></p>
<p>Para que seja <code>VERDADEIRO</code> o resultado duas expressões ligadas pelo conector <code>-a</code> é necessário que ambas sejam verdadeiras, o que não é o caso do exemplo acima. Assim o resultado final foi <code>FALSO</code> sendo então o <code>else</code> corretamente executado.</p>
<p>Se quisermos escolher um CD que tenha faixas de 2 artistas diferentes, nos sentimos tentados a usar um <code>if</code> com o conector <code>-a</code>, mas é sempre bom lembrarmos que o <i>bash</i> nos dá muito recursos, e isso poderia ser feito de forma muito mais simples com um único comando <code>grep</code>, da seguinte maneira:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ grep Artista1 musicas | grep Artista2</div>
<p>Da mesma forma para escolhermos CDs que tenham a participação do <code>Artista1</code> e do <code>Artista2</code>, não é necessário montarmos um if com o conector <code>-o</code>. O <code>egrep</code> (ou <code>grep -E</code>, sendo este mais aconselhável) também resolve isso para nós. Veja como:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ egrep (Artista1|Artista2) musicas</div>
<p>Ou (nesse caso específico) o próprio <code>grep</code> puro e simples poderia nos quebrar o galho:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ grep Artista[12] musicas</div>
<p>No <code>egrep</code> acima, foi usada uma expressão regular, onde a barra vertical (<code>|</code>) trabalha como um <code>OU</code> lógico e os parênteses são usados para limitar a amplitude deste <code>OU</code>. Já no <code>grep</code> da linha seguinte, a palavra <code>Artista</code> deve ser seguida por um dos valores da lista formada pelos colchetes (<code>[ ]</code>), isto é, <code>1</code> ou <code>2</code>.</p>
<p>- Tá legal, eu aceito o argumento, o <code>if</code> do <i>Shell</i> é muito mais poderoso que os outros caretas, mas cá pra nós, essa construção de <code>if test ...</code> é muito esquisita, é pouco legível.</p>
<p>- É você tem razão, eu também não gosto disso e acho que ninguém gosta. Acho que foi por isso, que o <i>Shell</i> incorporou outra sintaxe que substitui o comando <code>test</code>.</p>
<p>Exemplos:</p>
<p>Para isso vamos pegar aquele exemplo para fazer uma troca de diretórios, que era assim:</p>
<pre>    if  test ! -d lmb
    then
        mkdir lmb
    fi
    cd lmb</pre>
<p>e utilizando a nova sintaxe, vamos fazê-lo assim:</p>
<pre>    if  [ ! -d lmb ]
    then
        mkdir lmb
    fi
    cd lmb</pre>
<p>Ou seja, o comando <code>test</code> pode ser substituído por um par de colchetes (<code>[ ]</code>), separados por espaços em branco dos argumentos, o que aumentará enormemente a legibilidade, pois o comando <code>if</code> irá ficar com a sintaxe semelhante à das outras linguagens e por isso este será o modo que o comando <code>test</code> será usado daqui para a frente.</p>
<h2><a title="Querida_Encolheram_o_Comando_Con" name="Querida_Encolheram_o_Comando_Con"></a> Querida, Encolheram o Comando Condicional</h2>
<p>Se você pensa que acabou, está muito enganado. Repare a tabela (tabela verdade) a seguir:</p>
<table class="twikiTable" border="0" cellpadding="4" cellspacing="1">
<tr>
<th class="twikiFirstCol" align="center" bgcolor="#0000ff"><b><font color="#ffff00">Valores Booleanos</font></b></th>
<th align="center" bgcolor="#0000ff"><b><font color="#ffff00">E</font></b></th>
<th align="center" bgcolor="#0000ff"><b><font color="#ffff00">OU</font></b></th>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd">VERDADEIRO-VERDADEIRO</td>
<td align="center" bgcolor="#dddddd">VERDADEIRO</td>
<td align="center" bgcolor="#dddddd">VERDADEIRO</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb">VERDADEIRO-FALSO</td>
<td align="center" bgcolor="#bbbbbb">FALSO</td>
<td align="center" bgcolor="#bbbbbb">VERDADEIRO</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd">FALSO-VERDADEIRO</td>
<td align="center" bgcolor="#dddddd">FALSO</td>
<td align="center" bgcolor="#dddddd">VERDADEIRO</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb">FALSO-FALSO</td>
<td align="center" bgcolor="#bbbbbb">FALSO</td>
<td align="center" bgcolor="#bbbbbb">FALSO</td>
</tr>
</table>
<p>Ou seja, quando o conector é <code>E</code> e a primeira condição é verdadeira, o resultado final pode ser <code>VERDADEIRO</code> ou <code>FALSO</code>, dependendo da segunda condição, já no conector <code>OU</code>, caso a primeira condição seja verdadeira, o resultado sempre será <code>VERDADEIRO</code> e se a primeira for falsa, o resultado dependerá da segunda condição.</p>
<p>Ora, os caras que desenvolveram o interpretador não são bobos e estão sempre tentando otimizar ao máximo os algoritmos. Portanto, no caso do conector <code>E</code>, a segunda condição não será avaliada, caso a primeira seja falsa, já que o resultado será sempre <code>FALSO</code>. Já com o <code>OU</code>, a segunda será executada somente caso a primeira seja falsa.</p>
<p>Aproveitando disso, criaram uma forma abreviada de fazer testes. Batizaram o conector <code>E</code> de <code>&amp;&amp;</code> e o <code>OU</code> de <code>||</code> e para ver como isso funciona, vamos usá-los como teste no nosso velho exemplo de trocarmos de diretório, que em sua última versão estava assim:</p>
<pre>    if  [ ! -d lmb ]
    then
        mkdir lmb
    fi
    cd lmb</pre>
<p>Isso também poderia ser escrito da seguinte maneira:</p>
<pre>    [ ! -d lmb ] &amp;&amp; mkdir lmb
    cd lmb</pre>
<p>Ou ainda retirando a negação (<code>!</code>):</p>
<pre>    [ -d lmb ] || mkdir lmb
    cd lmb</pre>
<p>No primeiro caso, se o primeiro comando (o <code>test</code> que está representado pelos colchetes) for bem sucedido, isto é, não existir o diretório <code>lmb</code>, o <code>mkdir</code> será efetuado porque a primeira condição era verdadeira e o conector era <code>E</code>.</p>
<p>No exemplo seguinte, testamos se o diretório <code>lmb</code> existia (no anterior testamos se ele não existia) e caso isso fosse verdade, o <code>mkdir</code> não seria executado porque o conector era <code>OU</code>. Outra forma:</p>
<p><code>cd lmb || mkdir lmb</code></p>
<p>Neste caso, se o <code>cd</code> fosse mal sucedido, seria criado o diretório <code>lmb</code> mas não seria feito o <code>cd</code> para dentro dele. Para executarmos mais de um comando desta forma, é necessário fazermos um grupamento de comandos, e isso se consegue com o uso de chaves (<code>{ }</code>). Veja como seria o correto:</p>
<pre>    cd lmb ||
        {
        mkdir lmb
        cd lmb
        }</pre>
<p>Ainda não está legal, porque caso o diretório não exista, o <code>cd</code> dará a mensagem de erro correspondente. Então devemos fazer:</p>
<pre>    cd lmb 2&gt; /dev/null ||
        {
        mkdir lmb
        cd lmb
        }</pre>
<p>Como você viu o comando <code>if</code> nos permitiu fazer um <code>cd</code> seguro de diversas maneiras. É sempre bom lembrarmos que o seguro a que me referi é no tocante ao fato de que ao final da execução você sempre estará dentro de <code>lmb</code>, desde que você tenha permissão entrar em <code>lmb</code>, permissão para criar um diretório em <code>../lmb</code>, haja espaço em disco, &#8230;</p>
<h2><a title="E_tome_de_test" name="E_tome_de_test"></a> E tome de test</h2>
<p>Ufa! Você pensa que acabou? Ledo engano! Ainda tem uma forma de <code>test</code> a mais. Essa é legal porque ela te permite usar padrões para comparação. Estes padrões atendem às normas de Geração de Nome de Arquivos (<i>File Name Generation</i>, que são ligeiramente parecidas com as Expressões Regulares, mas não podem ser confundidas com estas). A diferença de sintaxe deste para o <code>test</code> que acabamos de ver é que esse trabalha com dois pares de colchete da seguinte forma:</p>
<p><code>[[ expressão ]]</code></p>
<p>Onde <code>expressão</code> é uma das que constam na tabela a seguir:</p>
<table class="twikiTable" border="0" cellpadding="4" cellspacing="1">
<tr>
<th colspan="2" class="twikiFirstCol" align="center" bgcolor="#0000ff"><b><font color="#ffff00">Expressões Condicionais Para Padrões</font></b></th>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><b>Expressão</b></td>
<td bgcolor="#dddddd"><b>Retorna</b></td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#bbbbbb"><code>cadeia == padrão</code><br />
<code>cadeia1 = padrao</code></td>
<td bgcolor="#bbbbbb">Verdadeiro se <code>cadeia1</code> casa com <code>padrão</code></td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><code>cadeia1 != padrao</code></td>
<td bgcolor="#dddddd">Verdadeiro se <code>cadeia1</code> não casa com <code>padrao</code>.</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#bbbbbb"><code>cadeia1 &lt; cadeia1</code></td>
<td bgcolor="#bbbbbb">Verdadeiro se <code>cadeia1</code> vem antes de <code>cadeia1</code> alfabeticamente.</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><code>cadeia1 &gt; cadeia1</code></td>
<td bgcolor="#dddddd">Verdadeiro se <code>cadeia1</code> vem depois de <code>cadeia1</code> alfabeticamente</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#bbbbbb"><code>expr1 &amp;&amp; expr2</code></td>
<td bgcolor="#bbbbbb">&#8220;E&#8221; lógico, verdadeiro se ambos <code>expr1</code> e <code>expr2</code> são verdadeiros</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><code>expr1 ¦¦ expr2</code></td>
<td bgcolor="#dddddd">&#8220;OU&#8221; lógico, verdadeiro se <code>expr1</code> ou <code>expr2</code> for verdadeiro</td>
</tr>
</table>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo $H<font color="#ffffff"><br />
13</font><br />
$ [[ $H == [0-9] || $H == 1[0-2] ]] || echo Hora inválida<font color="#ffffff"><br />
Hora inválida</font><br />
$H=12<br />
$ [[ $H == [0-9] || $H == 1[0-2] ]] || echo Hora inválida<br />
$</div>
<p>Neste exemplo, testamos se o conteúdo da variável <code>$H</code> estava compreendido entre zero e nove <code>([0-9])</code> ou <code>(||)</code> se estava entre dez e doze <code>(1[0-2])</code>, dando uma mensagem de erro caso não fosse.</p>
<p>Exemplos:</p>
<p>Para saber se uma variável tem o tamanho de um e somente um caractere, faça:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ var=a<br />
$ [[ $var == ? ]] &amp;&amp; echo var tem um caractere<font color="#ffffff"><br />
var tem um caractere</font><br />
$ var=aa<br />
$ [[ $var == ? ]] &amp;&amp; echo var tem um caractere<br />
$</div>
<p>Como você pode imaginar, este uso de padrões para comparação, aumenta muito o poderio do comando <code>test</code>. No início deste papo, antes do último chope, afirmamos que o comando <code>if</code> do interpretador <i>Shell</i> é mais poderoso que o seu similar em outras linguagens. Agora que conhecemos todo o seu espectro de funções, diga-me: você concorda ou não com esta assertiva?</p>
<h2><a title="Acaso_Casa_com_case" name="Acaso_Casa_com_case"></a> Acaso Casa com case</h2>
<p>Vejamos um exemplo didático: dependendo do valor da variável <code>$opc</code> o <i>script</i> deverá executar uma uma das opções: inclusão, exclusão, alteração ou fim. Veja como ficaria este fragmento de <i>script</i>:</p>
<pre>    if  [ $opc -eq 1 ]
    then
        inclusao
    elif [ $opc -eq 2 ]
    then
        exclusao
    elif [ $opc -eq 3 ]
    then
        alteracao
    elif [ $opc -eq 4 ]
    then
        exit
    else
        echo Digite uma opção entre 1 e 4
    fi</pre>
<p>Neste exemplo você viu o uso do <code>elif</code> com um <code>else if</code>, esta á a sintaxe válida e aceita, mas poderíamos fazer melhor, e isto seria com o comando <code>case</code>, que tem a sintaxe a seguir:</p>
<pre>    case $var in
        padrao1) cmd1
                 cmd2
                 cmdn ;;
        padrao2) cmd1
                 cmd2
                 cmdn ;;
        padraon) cmd1
                 cmd2
                 cmdn ;;
    esac</pre>
<p>Onde a variável <code>$var</code> é comparada aos padrões <code>padrao1, ..., padraon</code> e caso um deles atenda, o bloco de comandos <code>cmd1, ..., cmdn</code> correspondente é executado até encontrar um duplo ponto-e-vírgula (<code>;;</code>), quando o fluxo do programa se desviará para instrução imediatamente após o <code>esac</code>.</p>
<p>Na formação dos padrões, são aceitos os seguintes caracteres:</p>
<table class="twikiTable" border="0" cellpadding="4" cellspacing="1">
<tr>
<th colspan="2" class="twikiFirstCol" align="center" bgcolor="#0000ff"><b><font color="#ffff00">Caracteres Para Formação de Padrões</font></b></th>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><b>Caractere</b></td>
<td bgcolor="#dddddd"><b>Significado</b></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>*</code></td>
<td bgcolor="#bbbbbb">Qualquer caractere ocorrendo zero ou mais vezes</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><code>?</code></td>
<td bgcolor="#dddddd">Qualquer caractere ocorrendo uma vez</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>[...]</code></td>
<td bgcolor="#bbbbbb">Lista de caracteres</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><code>¦</code></td>
<td bgcolor="#dddddd"><code>OU</code> lógico</td>
</tr>
</table>
<p>Para mostrar como fica melhor, vamos repetir o exemplo anterior, só que desta vez usaremos o <code>case</code> e não o <code>if ... elif ... else ... fi</code>.</p>
<pre>    case $opc in
        1) inclusao ;;
        2) exclusao ;;
        3) alteracao ;;
        4) exit ;;
        *) echo Digite uma opção entre 1 e 4
    esac</pre>
<p>Como você deve ter percebido, eu usei o asterisco como a última opção, isto é, se o asterisco atende a qualquer coisa, então ele servirá para qualquer coisa que não esteja no intervalo de 1 a 4. Outra coisa a ser notada é que o duplo ponto-e-vírgula não é necessário antes do <code>esac</code>.</p>
<p>Exemplos:</p>
<p>Vamos agora fazer um <i>script</i> mais radical. Ele te dará bom dia, boa tarde ou boa noite dependendo da hora que for executado, mas primeiramente veja estes comandos:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ date<font color="#ffffff"><br />
Tue Nov  9 19:37:30 BRST 2004</font><br />
$ date +%H<font color="#ffffff"><br />
19</font></div>
<p>O comando <code>date</code> informa a data completa do sistema, mas ele tem diversas opções para seu mascaramento. Neste comando, a formatação começa com um sinal de mais (<code>+</code>) e os caracteres de formatação vêm após um sinal de percentagem (<code>%</code>), assim o <code>%H</code> significa a hora do sistema. Dito isso vamos ao exemplo:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat boasvindas.sh<font color="#ffffff"><br />
#!/bin/bash<br />
#  Programa bem educado que<br />
#  dá bom-dia, boa-tarde ou<br />
#  boa-noite conforme a hora<br />
Hora=$(date +%H)<br />
case $Hora in<br />
0? | 1[01]) echo Bom Dia<br />
;;<br />
1[2-7]    ) echo Boa Tarde<br />
;;<br />
*         ) echo Boa Noite<br />
;;<br />
esac<br />
exit</font></div>
<p>Peguei pesado, né? Que nada vamos esmiuçar a resolução caso-a-caso (ou seria case-a-case? <img src="http://twiki.softwarelivre.org/pub/TWiki/SmiliesPlugin/smile.gif" alt="smile" border="0" /> )</p>
<p><code>0? | 1[01]</code> &#8211; Significa zero seguido de qualquer coisa (<code>?</code>), ou (<code>|</code>) um seguido de zero ou um (<code>[01]</code>) ou seja, esta linha pegou 01, 02, &#8230; 09, 10 e 11;</p>
<p><code>1[2-7]    </code> &#8211; Significa um seguido da lista de dois a sete, ou seja, esta linha pegou 12, 13, &#8230; 17;</p>
<p><code>*         </code> &#8211; Significa tudo que não casou com nenhum dos padrões anteriores.</p>
<p>- Cara, até agora eu falei muito e bebi pouco. Agora eu vou te passar um exercício para você fazer em casa e me dar a resposta da próxima vez que nos encontrarmos aqui no botequim, tá legal?</p>
<p>- Tá, mas antes informe ao pessoal que está acompanhando este curso conosco como eles podem te encontrar para fazer críticas, contar piada, convidar para o chope, curso ou palestra ou até mesmo para falar mal dos políticos.</p>
<p>- É fácil, meu e-mail é <a href="mailto:julio.neves@gmail.com?Subject=Duvidas%20Papo%20de%20botequim">julio.neves@gmail.com</a>, mas pare de me embromar que eu não vou esquecer de te passar o <i>script</i> para fazer. É o seguinte: quero que você faça um programa que receberá como parâmetro o nome de um arquivo e que quando executado salvará este arquivo com o nome original seguido de um til (<code>~</code>) e colocará este arquivo dentro do vi (o melhor editor que se tem notícia) para ser editado. Isso é para ter sempre a última cópia boa deste arquivo caso o cara faça alterações indevidas. Obviamente, você fará as críticas necessárias, como verificar se foi passado um parâmetro, se o arquivo passado existe, &#8230; Enfim, o que te der na telha e você achar que deve constar do <i>script</i>. Deu prá entender?</p>
<p>- Hum, hum&#8230;</p>
<p>- Chico! Traz mais um sem colarinho que o cara aqui já está dando para entender! <img src="http://twiki.softwarelivre.org/pub/TWiki/SmiliesPlugin/smile.gif" alt="smile" border="0" /></p>
<p>Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em <i>Shell</i> que mande um e-mail para a nossa <a href="mailto:treinamentos@festivalsoftwarelivre.org?Subject=Curso%20de%20Shell%20com%20Julio%20Neves">gerencia de treinamento</a> para informar-se.</p>
<p>Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para <a href="mailto:julioneves@openoffice.org?Subject=D%C3%BAvidas%20Papo%20de%20Botequim">mim</a>.</p>
<p>Valeu!</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/jneves.wordpress.com/14/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/jneves.wordpress.com/14/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jneves.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jneves.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jneves.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jneves.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jneves.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jneves.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jneves.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jneves.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jneves.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jneves.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jneves.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jneves.wordpress.com/14/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jneves.wordpress.com/14/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jneves.wordpress.com/14/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=14&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/53f0649d2d6a9b19b90abd0575ee5c7c?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">jneves</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_atencao.gif" medium="image">
			<media:title type="html">Pinguim com placa de atenção</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" medium="image">
			<media:title type="html">Pinguim com placa de dica</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWiki/SmiliesPlugin/smile.gif" medium="image">
			<media:title type="html">smile</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWiki/SmiliesPlugin/smile.gif" medium="image">
			<media:title type="html">smile</media:title>
		</media:content>
	</item>
		<item>
		<title>Papo de Botequim &#8211; Parte 5</title>
		<link>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-5/</link>
		<comments>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-5/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 16:26:28 +0000</pubDate>
		<dc:creator>jneves</dc:creator>
				<category><![CDATA[Shell]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[exit]]></category>
		<category><![CDATA[cat]]></category>
		<category><![CDATA[echo]]></category>
		<category><![CDATA[loop]]></category>
		<category><![CDATA[for]]></category>
		<category><![CDATA[let]]></category>
		<category><![CDATA[/dev/null]]></category>
		<category><![CDATA[mkdir]]></category>
		<category><![CDATA[wc]]></category>
		<category><![CDATA[++]]></category>

		<guid isPermaLink="false">http://jneves.wordpress.com/?p=13</guid>
		<description><![CDATA[Comandos de Loop (ou laço) O comando for Primeira sintaxe do comando for Segunda sintaxe do comando for Terceira sintaxe do comando for - Fala cara! E as idéias estão em ordem? Já fundiu a cuca ou você ainda aguenta mais Shell? - Guento! Tô gostando muito! Gostei tanto que até caprichei no exercício que [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=13&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div class="twikiToc">
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo005#Comandos_de_Loop_ou_la%C3%A7o"> Comandos de Loop (ou laço)</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo005#O_comando_for"> O comando for</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo005#Primeira_sintaxe_do_comando_for"> Primeira sintaxe do comando for</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo005#Segunda_sintaxe_do_comando_for"> Segunda sintaxe do comando for</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo005#Terceira_sintaxe_do_comando_for"> Terceira sintaxe do comando for</a></li>
</ul>
</li>
</ul>
</li>
</ul>
</div>
<p>- Fala cara! E as idéias estão em ordem? Já fundiu a cuca ou você ainda aguenta mais <i>Shell</i>?</p>
<p>- Guento! Tô gostando muito! Gostei tanto que até caprichei no exercício que você passou. Lembra que você me pediu para fazer um programa que receberia como parâmetro o nome de um arquivo e que quando executado salvaria este arquivo com o nome original seguido de um til (<code>~</code>) e colocaria este arquivo dentro do <code>vi</code>?</p>
<p>- Claro que lembro, me mostre e explique como você fez.</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat vira<font color="#ffffff"><br />
#!/bin/bash<br />
#<br />
#  vira &#8211; vi resguardando arquivo anterior<br />
#         == =            =<br />
</font><br />
<font color="#ffffff"># Verificando se foi passado 1 parametro<br />
if  [ "$#" -ne 1 ]<br />
then<br />
echo &#8220;Erro -&gt; Uso: $0 &#8220;<br />
exit 1<br />
fi<br />
</font><br />
<font color="#ffffff">Arq=$1<br />
# Caso o arquivo não exista, nao ha copia para ser salva<br />
if  [ ! -f "$Arq" ]<br />
then<br />
vi $Arq<br />
exit 0<br />
fi<br />
</font><br />
<font color="#ffffff"># Se nao puder alterar o arquivo vou usar o vi para que?<br />
if  [ ! -w "$Arq" ]<br />
then<br />
echo &#8220;Voce nao tem direito de gravacao em $Arq&#8221;<br />
exit 2<br />
fi<br />
</font><br />
<font color="#ffffff"># Ja que esta tudo OK, vou salvar a copia e chamar o vi<br />
cp -f $Arq $Arq~<br />
vi $Arq<br />
exit 0</font></div>
<p>- É, beleza! Mas me diz uma coisa: porque você terminou o programa com um <code>exit 0</code>?</p>
<p>- Ahhh! Eu descobri que o número após o <code>exit</code> resultará no código de retorno do programa (o <code>$?</code>, lembra?), e desta forma, como foi tudo bem sucedido, ele encerraria com o <code>$? = 0</code>. Porém se você observar, verá que caso o programa não tenha recebido o nome do arquivo ou caso o operador não tivesse direito de gravação sobre este arquivo, o código de retorno (<code>$?</code>) seria diferente do zero.</p>
<p>- Grande garoto, aprendeu legal, mas é bom deixar claro que <code>exit 0</code>, simplesmente <code>exit</code> ou não colocar <code>exit</code>, produzem igualmente um código de retorno (<code>$?</code>) igual a zero. Agora vamos falar sobre as instruções de <i>loop</i> ou laço, mas antes vou passar o conceito de bloco de programa.</p>
<p>Até agora já vimos alguns blocos de programa. Quando te mostrei um exemplo para fazer um <code>cd</code> para dentro de um diretório que era assim:</p>
<pre>cd lmb 2&gt; /dev/null ||
    {
    mkdir lmb
    cd lmb
    }</pre>
<p>O fragmento contido entre as duas chaves (<code>{}</code>), forma um bloco de comandos. Também neste exercício que acabamos de ver, em que salvamos o arquivo antes de editá-lo, existem vários blocos de comandos compreendidos entre os <code>then</code> e os <code>fi</code> do <code>if</code>.</p>
<p>Um bloco de comandos também pode estar dentro de um <code>case</code>, ou entre um <code>do</code> e um <code>done</code>.</p>
<p>- Peraí Julio, que <code>do</code> e <code>done</code> é esse, não me lembro de você ter falado nisso e olha estou prestando muita atenção&#8230;</p>
<p>- Pois é, ainda não havia falado porque não havia chegado o momento propício. Todas as instruções de <i>loop</i> ou laço, executam os comandos do bloco compreendido entre o <code>do</code> e o <code>done</code>.</p>
<h2><a title="Comandos_de_Loop_ou_laço" name="Comandos_de_Loop_ou_laço"></a><a title="Comandos_de_Loop_ou_laço_" name="Comandos_de_Loop_ou_laço_"></a> Comandos de <i>Loop</i> (ou laço)</h2>
<p>As instruções de <i>loop</i> ou laço são o <code>for</code>, o <code>while</code> e o <code>until</code> que passarei a te explicar uma-a-uma a partir de agora.</p>
<h3><a title="O_comando_for" name="O_comando_for"></a> O comando for</h3>
<p>Se você está habituado a programar, certamente já conhece o comando <code>for</code>, mas o que você não sabe é que o <code>for</code>, que é uma instrução intrinseca do <i>Shell</i> (isto significa que o código fonte do comando faz parte do código fonte do <i>Shell</i>, ou seja em bom programês é um <i>built-in</i>), é muito mais poderoso que os seus correlatos das outras linguagens.</p>
<p>Vamos entender a sua sintaxe, primeiramente em português e depois como funciona no duro.</p>
<pre>    para var em val1 val2 ... valn
    faça
        cmd1
        cmd2
        cmdn
    feito</pre>
<p>Onde a variável <code>var</code> assume cada um dos valores da lista <code>val1 val2 ... valn</code> e para cada um desses valores executa o bloco de comandos formado por <code>cmd1</code>, <code>cmd2</code> e <code>cmdn</code></p>
<p>Agora que já vimos o significado da instrução em português, vejamos a sintaxe correta:</p>
<h4><a title="Primeira_sintaxe_do_comando_for" name="Primeira_sintaxe_do_comando_for"></a> Primeira sintaxe do comando for</h4>
<pre>    for var in val1 val2 ... valn
    do
        cmd1
        cmd2
        cmdn
    done</pre>
<p>Vamos direto para os exemplos, para entender direito o funcionamento deste comando. Vamos escrever um <i>script</i> para listar todos os arquivos do nosso diretório separados por dois-pontos, mas primeiro veja:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo *<font color="#ffffff"><br />
ArqDoDOS.txt1 confuso incusu logado musexc musicas musinc muslist</font></div>
<p>Isto é, o <i>Shell</i> viu o asterisco (<code>*</code>) expandindo-o com o nome de todos os arquivos do diretório e o comando <code>echo</code> jogou-os para a tela separados por espaços em branco. Visto isso vamos ver como resolver o problema a que nos propuzemos:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat testefor1<font color="#ffffff"><br />
#!/bin/bash<br />
# 1o. Prog didático para entender o for<br />
</font><br />
<font color="#ffffff">for Arq in *<br />
do<br />
echo -n $Arq:     # A opcao -n eh para nao saltar linha<br />
done</font></div>
<p>Então vamos executá-lo:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ testefor1<font color="#ffffff"><br />
ArqDoDOS.txt1:confuso:incusu:logado:musexc:musicas:musinc:muslist:</font>$</div>
<p>Como você viu o <i>Shell</i> transformou o asterísco (que odeia ser chamado de asterístico) em uma lista de arquivos separados por espaços em branco. quando o <code>for</code> viu aquela lista, ele disse: &#8220;Opa, lista separadas por espaços é comigo mesmo!&#8221;</p>
<p>O bloco de comandos a ser executado era somente o <code>echo</code>, que com a opção <code>-n</code> listou a variável <code>$Arq</code> seguida de dois-pontos (<code>:</code>), sem saltar a linha. O cifrão (<code>$</code>) do final da linha da execução é o <i>prompt</i>. que permaneceu na mesma linha também em função da opção <code>-n</code>. Outro exemplo simples (por enquanto):</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat testefor2<font color="#ffffff"><br />
#!/bin/bash<br />
# 2o. Prog didático para entender o for<br />
</font><br />
<font color="#ffffff">for Palavra in Papo de Botequim<br />
do<br />
echo $Palavra<br />
done</font></div>
<p>E executando vem:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ testefor2<font color="#ffffff"><br />
Papo<br />
de<br />
Botequim</font></div>
<p>Como você viu, este exemplo é tão bobo e simples como o anterior, mas serve para mostrar o comportamento básico do <code>for</code>.</p>
<p>Veja só a força do <code>for</code>: ainda estamos na primeira sintaxe do comando e já estou mostrando novas formas de usá-lo. Lá atrás eu havia falado que o <code>for</code> usava listas separadas por espaços em branco, mas isso é uma meia verdade, era só para facilitar a compreensão.</p>
<p>No duro, as listas não são obrigatóriamente separadas por espaços mas antes de prosseguir, deixa eu te mostrar como se comporta uma variável do sistema chamada de <code>$IFS</code>. Repare seu conteúdo:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo &#8220;$IFS&#8221; | od -h<font color="#ffffff"><br />
0000000 0920 0a0a<br />
0000004</font></div>
<p>Isto é, mandei a variável (protegida da interpretação do <i>Shell</i> pelas aspas) para um <i>dump</i> hexadecimal (<code>od -h</code>) e resultou:</p>
<table class="twikiTable" border="0" cellpadding="4" cellspacing="1">
<tr>
<th colspan="2" class="twikiFirstCol" align="center" bgcolor="#0000ff"><b><font color="#ffff00">Conteúdo da Variável $IFS</font></b></th>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><b>Hexadecimal</b></td>
<td bgcolor="#dddddd"><b>Significado</b></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>09</code></td>
<td align="center" bgcolor="#bbbbbb"><code>&lt;TAB&gt;</code></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><code>20</code></td>
<td align="center" bgcolor="#dddddd"><code>&lt;ESPAÇO&gt;</code></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>0a</code></td>
<td align="center" bgcolor="#bbbbbb"><code>&lt;ENTER&gt;</code></td>
</tr>
</table>
<p>Onde o último <code>0a</code> foi proveniente do <code>&lt;ENTER&gt;</code> dado ao final do comando. Para melhorar a explicação, vamos ver isso de outra forma:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo &#8220;:$IFS:&#8221; | cat -vet<font color="#ffffff"><br />
: ^I$<br />
:$</font></div>
<p>Preste atenção na dica a seguir para entender a construção deste comando cat:</p>
<div style="border:1px dashed red;min-height:121px;background-color:#ffffcc;margin:1em;padding:1em;"><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" style="float:left;padding:0 8px 0 0;" alt="Pinguim com placa de dica" align="left" /> No comando <code>cat</code>, a opção <code>-e</code> representa o <code>&lt;ENTER&gt;</code> como um cifrão (<code>$</code>) e a opção <code>-t</code> representa o <code>&lt;TAB&gt;</code> como um <code>^I</code>. Usei os dois-pontos (<code>:</code>) para mostrar o início e o fim do <code>echo</code>. E desta forma, mais uma vez pudemos notar que os três caracteres estão presentes naquela variável.</div>
<p>Agora veja você, <code>IFS</code> significa <b><i>Inter Field Separator</i></b> ou, traduzindo, separador entre campos. Uma vez entendido isso, eu posso afirmar (porque vou provar) que o comando <code>for</code> não usa listas separadas por espaços em branco, mas sim pelo conteúdo da variável <code>$IFS</code>, cujo valor padrão (<i>default</i>) são esses caracteres que acabamos de ver. Para comprovarmos isso, vamos mostrar um <i>script</i> que recebe o nome do artista como parâmetro e lista as músicas que ele executa, mas primeiramente vamos ver como está o nosso arquivo <code>musicas</code>:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat musicas<font color="#ffffff"><br />
album 1^Artista1~Musica1:Artista2~Musica2<br />
album 2^Artista3~Musica3:Artista4~Musica4<br />
album 3^Artista5~Musica5:Artista6~Musica6<br />
album 4^Artista7~Musica7:Artista1~Musica3<br />
album 5^Artista9~Musica9:Artista10~Musica10</font></div>
<p>Em cima deste &#8220;leiaute&#8221; foi desenvolvido o <i>script</i> a seguir:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat listartista<font color="#ffffff"><br />
#!/bin/bash<br />
# Dado um artista, mostra as suas musicas<br />
</font><br />
<font color="#ffffff">if  [ $# -ne 1 ]<br />
then<br />
echo Voce deveria ter passado um parametro<br />
exit 1<br />
fi<br />
</font><br />
<font color="#ffffff">IFS=&#8221;<br />
:&#8221;<br />
</font><br />
<font color="#ffffff">for ArtMus in $(cut -f2 -d^ musicas)<br />
do<br />
echo &#8220;$ArtMus&#8221; | grep $1 &amp;&amp; echo $ArtMus | cut -f2 -d~<br />
done</font></div>
<p>O <i>script</i>, como sempre, começa testando se os parâmetros foram passados corretamente, em seguida o <code>IFS</code> foi setado para <code>&lt;ENTER&gt;</code> e dois-pontos (<code>:</code>) (como demonstram as aspas em linha diferentes), porque é ele que separa os blocos <code>Artistan~Musicam</code>. Desta forma, a variável <code>$ArtMus</code> irá receber cada um destes blocos do arquivo (repare que o <code>for</code> já recebe os registros sem o álbum em virtude do <code>cut</code> na sua linha). Caso encontre o parâmetro (<code>$1</code>) no bloco, o segundo <code>cut</code> listará somente o nome da música. Vamos executá-lo:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ listartista Artista1<font color="#ffffff"><br />
Artista1~Musica1<br />
Musica1<br />
Artista1~Musica3<br />
Musica3<br />
Artista10~Musica10<br />
Musica10</font></div>
<p>Êpa! Aconteceram duas coisas indesejáveis: os blocos também foram listados e a <code>Musica10</code> idem. Além do mais, o nosso arquivo de músicas está muito simples, na vida real, tanto a música quanto o artista têm mais de um nome. Suponha que o artista fosse uma dupla sertaneja chamada <i>Perereca &amp; Peteleca</i> (não gosto nem de dar a idéia com receio que isso se torne realidade:). Neste caso o <code>$1</code> seria Perereca e o resto deste lindo nome seria ignorado na pesquisa.</p>
<p>Para que isso não ocorresse, eu deveia passar o nome do artista entre aspas (<code>"</code>) ou alterar <code>$1</code> por <code>$@</code> (que significa todos os parâmetros passados), que é a melhor solução, mas neste caso eu teria que modificar a crítica dos parâmetros e o <code>grep</code>. A nova crítica não seria se eu passei um parâmetro, mas <b>pelo menos</b> um parâmetro e quanto ao <code>grep</code>, veja só o que resultaria após a substituição do <code>$*</code> (que entraria no lugar do <code>$1</code>) pelos parâmetros:</p>
<pre>    echo "$ArtMus" | grep perereca &amp; peteleca</pre>
<p>O que resultaria em erro. O correto seria:</p>
<pre>    echo "$ArtMus" | grep -i "perereca &amp; peteleca"</pre>
<p>Onde foi colocado a opção <code>-i</code> para que a pesquisa ignorasse maiúsculas e minúsculas e as aspas também foram inseridas para que o nome do artista fosse visto como uma só cadeia monolítica.</p>
<p>Ainda falta consertar o erro dele ter listado o <code>Artista10</code>. Para isso o melhor é dizer ao <code>grep</code> que a cadeia está no início de <code>$ArtMus</code> (a expressão regular para dizer que está no início é <code>^</code>) e logo após vem um til (<code>~</code>). É necessário também que se redirecione a saída do grep para <code>/dev/null</code> para que os blocos não sejam mais listados. Veja então a nova (e definitiva) cara do programa:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat listartista<font color="#ffffff"><br />
#!/bin/bash<br />
# Dado um artista, mostra as suas musicas<br />
# versao 2<br />
</font><br />
<font color="#ffffff">if  [ $# -eq 0 ]<br />
then<br />
echo Voce deveria ter passado pelo menos um parametro<br />
exit 1<br />
fi<br />
</font><br />
<font color="#ffffff">IFS=&#8221;<br />
:&#8221;<br />
</font><br />
<font color="#ffffff">for ArtMus in $(cut -f2 -d^ musicas)<br />
do<br />
echo &#8220;$ArtMus&#8221; | grep -i &#8220;^$@~&#8221; &gt; /dev/null &amp;&amp; echo $ArtMus | cut -f2 -d~<br />
done</font></div>
<p>Que executando vem:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ listartista Artista1<font color="#ffffff"><br />
Musica1<br />
Musica3</font></div>
<h4><a title="Segunda_sintaxe_do_comando_for" name="Segunda_sintaxe_do_comando_for"></a> Segunda sintaxe do comando for</h4>
<pre>    for var
    do
        cmd1
        cmd2
        cmdn
    done</pre>
<p>- Ué, sem o <code>in</code> como ele vai saber que valor assumir?</p>
<p>- Pois é, né? Esta construção a primeira vista parece xquisita mas é bastante simples. Neste caso, <code>var</code> assumirá um-a-um cada um dos parâmetros passados para o progama.</p>
<p>Vamos logo aos exemplos para entender melhor. Vamos fazer um <i>script</i> que receba como parâmetro um monte de músicas e liste seus autores:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat listamusica<font color="#ffffff"><br />
#!/bin/bash<br />
# Recebe parte dos nomes de musicas como parametro e<br />
# lista os interpretes. Se o nome for composto, deve<br />
# ser passado entre aspas.<br />
# ex. &#8220;Eu nao sou cachorro nao&#8221; &#8220;Churrasquinho de Mae&#8221;<br />
#<br />
if  [ $# -eq 0 ]<br />
then<br />
echo Uso: $0 musica1 [musica2] &#8230; [musican]<br />
exit 1<br />
fi<br />
IFS=&#8221;<br />
:&#8221;<br />
for Musica<br />
do<br />
echo $Musica<br />
Str=$(grep -i &#8220;$Musica&#8221; musicas) ||<br />
{<br />
echo &#8221;    Não encontrada&#8221;<br />
continue<br />
}<br />
for ArtMus in $(echo &#8220;$Str&#8221; | cut -f2 -d^)<br />
do<br />
echo &#8221;    $ArtMus&#8221; | grep -i &#8220;$Musica&#8221; | cut -f1 -d~<br />
done<br />
done</font></div>
<p>Da mesma forma que os outros, começamos o exercício com uma crítica sobre os parâmetros recebidos, em seguida fizemos um <code>for</code> em que a variável <code>$Musica</code> receberá cada um dos parâmetros passados, colocando em <code>$Str</code> todos os álbuns que contém as músicas passadas. Em seguida, o outro <code>for</code> pega cada bloco <code>Artista~Musica</code> nos registros que estão em <code>$Str</code> e lista cada artista que execute aquela música.</p>
<p>Como sempre vamos executá-lo para ver se funciona mesmo:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ listamusica musica3 Musica4 &#8220;Eguinha Pocotó&#8221;<font color="#ffffff"><br />
musica3<br />
Artista3<br />
Artista1<br />
Musica4<br />
Artista4<br />
Eguinha Pocotó<br />
Não encontrada</font></div>
<p>A listagem ficou feinha porque ainda não sabemos formatar a saída, mas qualquer dia desses, quando você souber posicionar o cursor, fazer negrito, trabalhar com cores e etc, faremos esta listagem novamente usando todas estas perfumarias e ela ficará muito <i>fashion</i>.</p>
<p>A esta altura dos acontecimentos você deve estar se perguntando: &#8220;E aquele <code>for</code> tradicional das outras linguagens em que ele sai contando a partir de um número, com um determinado incremento até alcançar uma condição?&#8221;</p>
<p>E é aí que eu te respondo: &#8220;Eu não te disse que o nosso <code>for</code> é mais porreta que os outros?&#8221; Para fazer isso existem duas formas:</p>
<p>1 &#8211; Com a primeira sintaxe que vimos, como nos exemplos a seguir direto no <i>prompt</i>:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ for i in $(seq 9)<br />
&gt; do<br />
&gt;     echo -n &#8220;$i &#8220;<br />
&gt; done<font color="#ffffff"><br />
1 2 3 4 5 6 7 8 9</font></div>
<p>Neste a variável <code>i</code> assumiu os inteiros de 1 a 9 gerados pelo comando <code>seq</code> e a opção <code>-n</code> do <code>echo</code> foi usada para não saltar linha a cada número listado (sinto-me ecologicamente correto por não gastar um monte de papel da revista quando isso pode ser evitado). Ainda usando o <code>for</code> com <code>seq</code>:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ for i in $(seq 3 9)<br />
&gt; do<br />
&gt;     echo -n &#8220;$i &#8220;<br />
&gt; done<font color="#ffffff"><br />
4 5 6 7 8 9</font></div>
<p>Ou ainda na forma mais completa do <code>seq</code>:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ for i in $(seq 0 3 9)<br />
&gt; do<br />
&gt;     echo -n &#8220;$i &#8220;<br />
&gt; done<font color="#ffffff"><br />
0 3 6 9</font></div>
<p>2 – A outra forma de fazer o desejado é com uma sintaxe muito semelhante ao <code>for</code> da linguagem C, como veremos a seguir.</p>
<h4><a title="Terceira_sintaxe_do_comando_for" name="Terceira_sintaxe_do_comando_for"></a> Terceira sintaxe do comando for</h4>
<pre>    for ((var=ini; cond; incr))
    do
        cmd1
        cmd2
        cmdn
    done</pre>
<p>Onde:</p>
<p><code>var=ini</code> &#8211;   Significa que a variável <code>var</code> começará de um valor inicial <i>ini</i>;<br />
<code>cond   </code>    &#8211;   Siginifica que o <i>loop</i> ou laço do <code>for</code> será executado enquanto <code>var</code> não atingir a condição <code>cond</code>;<br />
<code>incr   </code>    &#8211;   Significa o incremento que a variável <code>var</code> sofrerá em cada passada do <i>loop</i>.</p>
<p>Como sempre vamos aos exemplos que a coisa fica mais fácil:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ for ((i=1; i&lt;=9; i++))<br />
&gt; do<br />
&gt;     echo -n &#8220;$i &#8220;<br />
&gt; done<font color="#ffffff"><br />
1 2 3 4 5 6 7 8 9</font></div>
<p>Neste caso a variável <code>i</code> partiu do valor inicial <code>1</code>, o bloco de comando (neste caso somente o <code>echo</code>) será executado enquanto <code>i</code> menor ou igual (<code>&lt;=</code>) a <code>9</code> e o incremento de <code>i</code> será de <code>1</code> a cada passada do <i>loop</i>.</p>
<p>Repare que no <code>for</code> propriamente dito (e não no bloco de comandos) não coloquei um cifrão (<code>$</code>) antes do <code>i</code>, e a notação para incrementar (<code>i++</code>) é diferente do que vimos até agora. Isto é porque o uso de parênteses duplos (assim como o comando <code>let</code>) chama o interpretador aritmético do <i>Shell</i>, que é mais tolerante.</p>
<p>Como me referi ao comando <code>let</code>, só para mostrar como ele funciona e a versatilidade do <code>for</code>, vamos fazer a mesma coisa, porém omitindo a última parte do escopo do <code>for</code>, passando-a para o bloco de comandos.</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ for ((; i&lt;=9;))<br />
&gt; do<br />
&gt;     let i++<br />
&gt;     echo -n &#8220;$i &#8220;<br />
&gt; done<font color="#ffffff"><br />
1 2 3 4 5 6 7 8 9</font></div>
<p>Repare que o incremento saiu do corpo do <code>for</code> e passou para o bloco de comandos, repare também que quando usei o <code>let</code>, não foi necessário sequer inicializar a variável <code>$i</code>. Veja só os comandos a seguir dados diretamente no <i>prompt</i> para mostrar o que acabo de falar:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo $j$ let j++<br />
$ echo $j<font color="#ffffff"><br />
1</font></div>
<p>Ou seja, a variável <code>$j</code> sequer existia e no primeiro <code>let</code> assumiu o valor <code>0</code> (zero) para, após o incremento, ter  o valor <code>1</code>.</p>
<p>Veja só como as coisas ficam simples:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ for arq in *<br />
&gt; do<br />
&gt;     let i++<br />
&gt;     echo &#8220;$i -&gt; $Arq&#8221;<br />
&gt; done<font color="#ffffff"><br />
1 -&gt; ArqDoDOS.txt1<br />
2 -&gt; confuso<br />
3 -&gt; incusu<br />
4 -&gt; listamusica<br />
5 -&gt; listartista<br />
6 -&gt; logado<br />
7 -&gt; musexc<br />
8 -&gt; musicas<br />
9 -&gt; musinc<br />
10 -&gt; muslist<br />
11 -&gt; testefor1<br />
12 -&gt; testefor2</font></div>
<p>- Pois é amigo, tenho certeza que você já tomou um xarope do comando <code>for</code>. Por hoje chega, na próxima vez que nos encontrarmos falaremos sobre outras instruções de <i>loop</i>, mas eu gostaria que até lá você fizesse um pequeno <i>script</i> para contar a quantidade de palavras de um arquivo texto, cujo nome seria recebido por parâmetro.</p>
<p>OBS: Essa contagem tem de ser feita usando o comando for para se habituar ao seu uso. Não vale usar o <code>wc -w</code>.</p>
<p>- Aê Chico! Traz a saideira.</p>
<p>Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em <i>Shell</i> que mande um e-mail para a nossa <a href="mailto:treinamentos@festivalsoftwarelivre.org?Subject=Curso%20de%20Shell%20com%20Julio%20Neves">gerencia de treinamento</a> para informar-se.</p>
<p>Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para <a href="mailto:julioneves@openoffice.org?Subject=D%C3%BAvidas%20Papo%20de%20Botequim">mim</a>.</p>
<p>Valeu!</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/jneves.wordpress.com/13/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/jneves.wordpress.com/13/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jneves.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jneves.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jneves.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jneves.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jneves.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jneves.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jneves.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jneves.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jneves.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jneves.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jneves.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jneves.wordpress.com/13/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jneves.wordpress.com/13/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jneves.wordpress.com/13/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=13&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-5/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/53f0649d2d6a9b19b90abd0575ee5c7c?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">jneves</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" medium="image">
			<media:title type="html">Pinguim com placa de dica</media:title>
		</media:content>
	</item>
		<item>
		<title>Papo de Botequim &#8211; Parte 6</title>
		<link>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-6/</link>
		<comments>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-6/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 16:23:09 +0000</pubDate>
		<dc:creator>jneves</dc:creator>
				<category><![CDATA[Shell]]></category>
		<category><![CDATA[grep]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[sleep]]></category>
		<category><![CDATA[while]]></category>
		<category><![CDATA[if]]></category>
		<category><![CDATA[echo]]></category>
		<category><![CDATA[loop]]></category>
		<category><![CDATA[until]]></category>
		<category><![CDATA[fi]]></category>
		<category><![CDATA[for]]></category>
		<category><![CDATA[done]]></category>
		<category><![CDATA[let]]></category>
		<category><![CDATA[PID]]></category>
		<category><![CDATA[ps]]></category>
		<category><![CDATA[who]]></category>
		<category><![CDATA[pipeline]]></category>
		<category><![CDATA[break]]></category>
		<category><![CDATA[continue]]></category>
		<category><![CDATA[alias]]></category>

		<guid isPermaLink="false">http://jneves.wordpress.com/?p=12</guid>
		<description><![CDATA[Comandos de Loop ou Laço (Continuação) Um Pouco Mais de for e Matemática O comando while O comando until Atalhos no loop Comandos de Loop ou Laço (Continuação) - Fala cara! E aí, já tá sabendo tudo do comando for? Eu te deixei um exercício para treinar, se não me engano era para contar a [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=12&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div class="twikiToc">
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo006#Comandos_de_Loop_ou_La%C3%A7o_Continu"> Comandos de Loop ou Laço (Continuação)</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo006#Um_Pouco_Mais_de_for_e_Matem%C3%A1tic"> Um Pouco Mais de for e Matemática</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo006#O_comando_while"> O comando while</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo006#O_comando_until"> O comando until</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo006#Atalhos_no_loop"> Atalhos no loop</a></li>
</ul>
</li>
</ul>
</div>
<h2><a title="Comandos_de_Loop_ou_Laço_Continu" name="Comandos_de_Loop_ou_Laço_Continu"></a> Comandos de <i>Loop</i> ou Laço (Continuação)</h2>
<p>- Fala cara! E aí, já tá sabendo tudo do comando <code>for</code>? Eu te deixei um exercício para treinar, se não me engano era para contar a quantidade de palavras de um arquivo&#8230; Você fez?      &#8211; Claro! Tô empolgadão com essa linguagem, eu fiz da forma que você pediu, isto é sem usar o comando <code>wc</code> porque senão era mais mole ainda. Olha só como eu fi&#8230;</p>
<p>- Êpa! Perai! Você realmente está fissurado na linguagem, mas eu tô sequinho pra tomar um chope. Aê Chico, traz dois por favor. Um sem colarinho!</p>
<p>- Como eu ia dizendo olha a forma que eu fiz. É muito fácil&#8230;</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat contpal.sh<font color="#ffffff"><br />
#!/bin/bash<br />
# Script  meramente pedagógico cuja<br />
# função é contar a qtd de palavras<br />
# de um  arquivo.  Supõe-se  que as<br />
# palavras estão separadas entre si<br />
# por espaço,  ou .<br />
</font><br />
<font color="#ffffff">if  [ $# -ne 1 ]<br />
then<br />
echo uso: $0 /caminho/do/arquivo<br />
exit 2<br />
fi<br />
Cont=0<br />
for Palavra in $(cat $1)<br />
do<br />
Cont=$((Cont+1))<br />
done<br />
echo O arquivo $1 tem $Cont palavras.</font></div>
<p>Ou seja, o programa começa como sempre verificando se a passagem de parâmetros foi correta, em seguida o comando <code>for</code> se incumbe de pegar cada uma das palavras (lembre-se que o <code>$IFS</code> padrão (default) é branco, <code>&lt;TAB&gt;</code> e <code>&lt;ENTER&gt;</code>, que é exatamente o que desejamos para separar as palavras), incrementando a variável <code>$Cont</code>.</p>
<p>Vamos relembrar como é o arquivo <code>ArqDoDOS.txt</code>.</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat ArqDoDOS.txt<font color="#ffffff"><br />
Este arquivo<br />
foi gerado pelo<br />
DOS/Rwin e foi<br />
baixado por um<br />
ftp mal feito.</font></div>
<p>Agora vamos testar o programa passando este arquivo como parâmetro:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ contpal.sh ArqDoDOS.txt<font color="#ffffff"><br />
O arquivo ArqDoDOS.txt tem 14 palavras</font></div>
<p>- Beleza, funcionou legal!</p>
<h3><a title="Um_Pouco_Mais_de_for_e_Matemátic" name="Um_Pouco_Mais_de_for_e_Matemátic"></a> Um Pouco Mais de <code>for</code> e Matemática</h3>
<p>Voltando à vaca fria, na última vez que aqui estivemos, terminamos o nosso papo mostrando o <i>loop</i> de <code>for</code> a seguir:</p>
<pre>    for ((; i&lt;=9;))
    do
        let i++
        echo -n "$i "
    done</pre>
<p>Uma vez que chegamos neste ponto, creio ser bastante interessante citar que o Shell trabalha com o conceito de &#8220;Expansão Aritmética&#8221; (<i>Arithmetic Expansion</i>), da qual vou falar rapidamente porque na seção <a href="https://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarBirinaite#Aritm%E9tica_em_Shell" target="_blank">Tira Gosto</a> isso está muito bem mastigado.</p>
<p>A expansão aritmética é acionada por uma construção da forma:</p>
<p><code>$((expressão))</code></p>
<p>ou</p>
<p><code>let expressão</code></p>
<p>No último <code>for</code> citado usei a expansão das duas formas, mas não poderíamos seguir adiante sem saber que a expressão pode ser de uma das listadas a seguir:</p>
<table class="twikiTable" border="0" cellpadding="4" cellspacing="1">
<tr>
<th colspan="2" class="twikiFirstCol" align="center" bgcolor="#0000ff"><b><font color="#ffff00">Expansão Aritmética</font></b></th>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><b>Expressão</b></td>
<td align="center" bgcolor="#dddddd"><b>Resultado</b></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>id++ id--</code></td>
<td bgcolor="#bbbbbb">pós-incremento e pós-decremento de variáveis</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><code>++id -–id</code></td>
<td bgcolor="#dddddd">pré-incremento e pré-decremento de variáveis</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>**</code></td>
<td bgcolor="#bbbbbb">exponenciação</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><code>* / %</code></td>
<td bgcolor="#dddddd">multiplicação, divisão, resto da divisão</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>+ -</code></td>
<td bgcolor="#bbbbbb">adição, subtração</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><code>&lt;= &gt;= &lt; &gt;</code></td>
<td bgcolor="#dddddd">comparação</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>== !=</code></td>
<td bgcolor="#bbbbbb">igualdade, desigualdade</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><code>&amp;&amp;</code></td>
<td bgcolor="#dddddd">E lógico</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>||</code></td>
<td bgcolor="#bbbbbb">OU lógico</td>
</tr>
</table>
<p>- Mas você pensa que o papo de <i>loop</i> (ou laço) se encerra no comando <code>for</code>? Ledo engano amigo, vamos a partir de agora ver mais dois.</p>
<h3><a title="O_comando_while" name="O_comando_while"></a><a title="O_comando_while_" name="O_comando_while_"></a> O comando <code>while</code></h3>
<p>Todos os programadores conhecem este comando, porque ele é comum a todas as linguagens e nelas, o que normalmente ocorre é que um bloco de comandos é executado, <b>enquanto</b> (enquanto em ingles é <i>while</i>) uma determinada <b>condição</b> for verdadeira. Pois bem, isto é o que ocorre nas linguagens caretas! Em programação <i>Shell</i>, o bloco de comandos é executado <b>enquanto</b> um <b>comando</b> for verdadeiro. E é claro, se quiser testar uma condição use o comando <code>while</code> junto com o comando <code>test</code>, exatamente como você aprendeu a fazer no <code>if</code>, lembra?</p>
<p>Então a sintaxe do comando fica assim:</p>
<pre>    while comando
    do
        cmd1
        cmd2
        ...
        cmdn
    done</pre>
<p>e desta forma o bloco de comandos formado pelas instruções <code>cmd1</code>, <code>cmd2</code>,&#8230; e <code>cmdn</code> é executado enquanto a execução da instrução <code>comando</code> for bem sucedida.</p>
<p>Suponha a seguinte cena: tem uma tremenda gata me esperando e eu preso no trabalho sem poder sair porque o meu chefe, que é um pé no saco (aliás chefe-chato é uma redundância, né?:), ainda estava na sua sala, que fica bem na minha passagem para a rua.</p>
<p>Ele começou a ficar com as antenas (provavelmente instaladas na cabeça dele pela esposa) ligadas depois da quinta vez que passei pela sua porta e olhei para ver se já havia ido embora. Então voltei para a minha mesa e fiz, no servidor, um <i>script</i> assim:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat logaute.sh<font color="#ffffff"><br />
#!/bin/bash<br />
</font><br />
<font color="#ffffff"># Espero que a Xuxa não tenha<br />
# copyright de xefe e xato <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
</font><br />
<font color="#ffffff">while who | grep xefe<br />
do<br />
sleep 30<br />
done<br />
echo O xato se mandou, não hesite, dê exit e vá a luta</font></div>
<p>Neste <i>scriptizinho</i>, o comando <code>while</code> testa o <i>pipeline</i> composto pelo <code>who</code> e pelo <code>grep</code> e que será verdadeiro enquanto o <code>grep</code> localizar a palavra <code>xefe</code> na saída do <code>who</code>. Desta forma, o <i>script</i> dormirá por 30 segundos enquanto o chefe estiver logado (Argh!). Assim que ele se desconectar do servidor, o fluxo do <i>script</i> sairá do <i>loop</i> e dará a tão ansiada mensagem de liberdade.</p>
<p>Quando o executei adivinha o que aconteceu?</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ logaute.sh<font color="#ffffff"><br />
xefe  pts/0   Jan  4 08:46 (10.2.4.144)<br />
xefe  pts/0   Jan  4 08:47 (10.2.4.144)<br />
&#8230;<br />
xefe  pts/0   Jan  4 08:52 (10.2.4.144)</font></div>
<p>Isto é a cada 30 segundos seria enviado para a tela a saída do <code>grep</code>, o que não seria legal já que poluiria a tela do meu micro e a mensagem esperada poderia passar desapercebida. Para evitar isso já sabemos que a saída do <i>pipeline</i> tem que ser redirecionada para <code>/dev/null</code>.</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat logaute.sh<font color="#ffffff"><br />
#!/bin/bash<br />
</font><br />
<font color="#ffffff"># Espero que a Xuxa não tenha<br />
# copyright de xefe e xato <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /><br />
</font><br />
<font color="#ffffff">while who | grep xefe &gt; /dev/null<br />
do<br />
sleep 30<br />
done<br />
echo O xato se mandou, não hesite, dê exit e vá a luta</font></div>
<p>Agora quero montar um <i>script</i> que receba o nome (e eventuais parâmetros) de um programa que será executado em <i>background</i> e que me informe do seu término. Mas, para você entender este exemplo, primeiro tenho de mostar uma nova variável do sistema. Veja estes comandos diretos no <i>prompt</i>:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ sleep 10&amp;<font color="#ffffff"><br />
[1] 16317</font><br />
$ echo $!<font color="#ffffff"><br />
16317<br />
[1]+  Done                    sleep 10</font><br />
$ echo $!<font color="#ffffff"><br />
16317</font></div>
<p>Isto é, criei um processo em <i>background</i> para dormir por 10 segundos, somente para mostrar que a variável <code>$!</code> guarda o PID (<i>Process IDentification</i>) do último processo em <i>background</i>, mas repare após a linha do <code>done</code>, que a variável reteve o valor mesmo após o término deste processo.</p>
<p>Bem sabendo isso já fica mais fácil de monitorar qualquer processo em <i>background</i>. Veja só como:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat monbg.sh<font color="#ffffff"><br />
#!/bin/bash<br />
</font><br />
<font color="#ffffff"># Executa e  monitora um<br />
# processo em background<br />
</font><br />
<font color="#ffffff">$1 &amp;      # Coloca em backgroud<br />
while ps | grep -q $!<br />
do<br />
sleep 5<br />
done<br />
echo Fim do Processo $1</font></div>
<p>Este <i>script</i> é bastante similar ao anterior, mas tem uns macetes a mais, veja só: ele tem que ser executado em <i>background</i> para não prender o <i>prompt</i> mas o <code>$!</code> será o do programa passado como parâmetro já que ele foi colocado em <i>background</i> após o <code>monbg.sh</code> propriamente dito. Repare também a opção <code>-q</code> (<i>quiet</i>) do <code>grep</code>, ela serve para tranformá-lo num comando mineiro, isto é, para o <code>grep</code> &#8220;trabalhar em silêncio&#8221;. O mesmo resultado poderia ser obtido se a linha fosse <code>while ps | grep $! &gt; /dev/null</code>, como nos exemplos que vimos até agora.</p>
<div style="border:1px dashed red;min-height:121px;background-color:#ffffcc;margin:1em;padding:1em;"><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" style="float:left;padding:0 8px 0 0;" alt="Pinguim com placa de dica" align="left" />   Não esqueça: o <i>Bash</i> disponibiliza a variável <code>$!</code> que possui o <code>PID</code> (<i>Process IDentification</i>) do último processo executado em <i>background</i>.</div>
<p>Vamos melhorar o <code>musinc</code>, que é o nosso programa para incluir registros no arquivo <code>musicas</code>, mas antes preciso te ensinar a pegar um dado da tela, e já vou avisando: só vou dar uma pequena dica do comando <i>read</i> (que é quem pega o dado da tela) que seja o suficiente para resolver este nosso problema. Em uma outra rodada de chope vou te ensinar tudo sobre o assunto, inclusive como formatar tela, mas hoje estamos falando sobre <i>loops</i>.</p>
<p>A sintaxe do comando <code>read</code> que nos interessa por hoje é a seguinte:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ read -p &#8220;prompt de leitura&#8221; var</div>
<p>Onde <code>prompt de leitura</code> é o texto que você quer que apareça escrito na tela, e quando o  operador teclar o dado, ele irá para a variável <code>var</code>. Por exemplo:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ read -p &#8220;Título do Álbum: &#8221; Tit</div>
<p>Bem, uma vez entendido isso, vamos à especificação do nosso problema: faremos um programa que inicialmente lerá o nome do álbum e em seguida fara um <i>loop</i> de leitura, pegando a música e o artista. Este <i>loop</i> termina quando for informada uma música vazia, isto é, ao ser solicitada a digitação da música, o operador dá um simples <code>&lt;ENTER&gt;</code>. Para facilitar a vida do operador, vamos oferecer como <i>default</i> o mesmo nome do artista da música anterior (já que é normal que o álbum seja todo do mesmo artista) até que ele deseje alterá-lo. Vamos ver como ficou:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat musinc<font color="#ffffff"><br />
#!/bin/bash<br />
# Cadastra CDs (versao 4)<br />
#<br />
clear<br />
read -p &#8220;Título do Álbum: &#8221; Tit<br />
[ "$Tit" ] || exit 1 # Fim da execução se título vazio<br />
if grep &#8220;^$Tit^&#8221; musicas &gt; /dev/null<br />
then<br />
echo Este álbum já está cadastrado<br />
exit 1<br />
fi<br />
Reg=&#8221;$Tit^&#8221;<br />
Cont=1<br />
oArt=<br />
while true<br />
do<br />
echo Dados da trilha $Cont:<br />
read -p &#8220;Música: &#8221; Mus<br />
[ "$Mus" ] || break       # Sai se vazio<br />
read -p &#8220;Artista: $oArt // &#8221; Art<br />
[ "$Art" ] &amp;&amp; oArt=&#8221;$Art&#8221; # Se vazio Art anterior<br />
Reg=&#8221;$Reg$oArt~$Mus:&#8221;     # Montando registro<br />
Cont=$((Cont + 1))<br />
# A linha anterior tb poderia ser ((Cont++))<br />
done<br />
echo &#8220;$Reg&#8221; &gt;&gt; musicas<br />
sort musicas -o musicas</font></div>
<p>Este exemplo, começa com a leitura do título do álbum, que se não for informado, terminará a execução do programa. Em seguida um <code>grep</code> procura no início (<code>^</code>) de cada registro de musicas, o título informado seguido do separador (<code>^</code>) (que está precedido de uma contrabarra (<code></code>) para protegê-lo da interpretação do <i>Shell</i>).</p>
<p>Para ler os nomes dos artistas e as músicas do álbum, foi montado um <i>loop</i> de <code>while</code> simples, cujo único destaque é o fato de estar armazenando o artista da música anterior na variável <code>$oArt</code> que só terá o seu conteúdo alterado, quando algum dados for informado para a variável <code>$Art</code>, isto é, quando não teclou-se um simples <code>&lt;ENTER&gt;</code> para manter o artista anterior.</p>
<p>O que foi visto até agora sobre o <code>while</code> foi muito pouco. Este comando é muito utilizado, principalmente para leitura de arquivos, porém nos falta bagagem para prosseguir. Depois que aprendermos a ler, veremos esta instrução mais a fundo.</p>
<div style="border:1px dashed red;min-height:121px;background-color:#ffffcc;margin:1em;padding:1em;"><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" style="float:left;padding:0 8px 0 0;" alt="Pinguim com placa de dica" align="left" /> Leitura de arquivo significa ler um-a-um todos os registros, o que é sempre uma operação lenta. Fique atento para não usar o <code>while</code> quando seu uso for desnecessário. O <i>Shell</i> tem ferramentas como o <code>sed</code> e a família <code>grep</code> que vasculham arquivos de forma otimizada sem ser necessário o uso de comandos de <i>loop</i> para fazê-lo registro a registro (ou até palavra a palavra).</div>
<h3><a title="O_comando_until" name="O_comando_until"></a><a title="O_comando_until_" name="O_comando_until_"></a> O comando <code>until</code></h3>
<p>O comando <code>until</code> funciona exatamente igual ao <code>while</code>, porém ao contrário. Disse tudo mas não disse nada, né? É o seguinte: ambos testam comandos; ambos possuem a mesma sintaxe e ambos atuam em <i>loop</i>, porém enquanto o <code>while</code> executa o bloco de intruções do <i>loop</i> <b>enquanto</b> um comando for bem sucedido, o <code>until</code> executa o bloco do <i>loop</i> <b>até que</b> o comando seja bem sucedido. Parece pouca coisa mas a diferença é fundamental.</p>
<p>A sintaxe do comando é praticamente a mesma do <code>while</code>. Veja:</p>
<pre>    until comando
    do
        cmd1
        cmd2
        ...
        cmdn
    done</pre>
<p>E desta forma o bloco de comandos formado pelas instruções <code>cmd1</code>, <code>cmd2</code>,&#8230; e <code>cmdn</code> é executado até que a execução da instrução <code>comando</code> seja bem sucedida.</p>
<p>Como eu te disse, o <code>while</code> e <code>until</code> funcionam de forma antagônica e isso é muito fácil de demonstrar: em uma guerra sempre que se inventa uma arma, o inimigo busca uma solução para neutralizá-la. Baseado neste principio belicoso que o meu chefe, desenvolveu, no mesmo servidor que eu executava o <code>logaute.sh</code> um <i>script</i> para controlar o meu horário de chegada.</p>
<p>Um dia deu um problema da rede, ele me pediu para dar uma olhada no micro dele e me deixou sozinho em sua sala. Imediatamente comecei a bisbilhotar seus arquivos &#8211; porque guerra é guerra &#8211; e veja só o que descobri:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$cat chegada.sh<font color="#ffffff"><br />
#!/bin/bash<br />
</font><br />
<font color="#ffffff">until who | grep julio<br />
do<br />
sleep 30<br />
done<br />
echo $(date &#8220;+ Em %d/%m às %H:%Mh&#8221;) &gt;&gt; relapso.log</font></div>
<p>Olha que safado! O cara estava montando um <i>log</i> com os horários que eu chegava, e ainda por cima chamou o arquivo que me monitorava de <code>relapso.log</code>! O que será que ele quis dizer com isso?</p>
<p>Neste <i>script</i>, o <i>pipeline</i> <code>who | grep julio</code>, será bem sucedido somente quando <code>julio</code> for encontrado no comando <code>who</code>, isto é, quando eu me &#8220;logar&#8221; no servidor. Até que isso aconteça, o comando <code>sleep</code>, que forma o bloco de instruções do <code>until</code>, porá o programa em espera por 30 segundos. Quando este loop encerrar-se, será dada uma mensagem para o <code>relapso.log</code> (ARGHH!). Supondo que no dia 20/01 eu me loguei às 11:23 horas, a mensagem seria a seguinte:</p>
<p><code>Em 20/01 às 11:23h</code></p>
<p>Quando vamos cadastrar músicas, o ideal seria que pudéssemos cadastrar diversos CDs, e na última versão que fizemos do <code>musinc</code>, isso não ocorre, a cada CD que cadastramos o programa termina. Vejamos como melhorá-lo:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat musinc<font color="#ffffff"><br />
#!/bin/bash<br />
# Cadastra CDs (versao 5)<br />
#<br />
Para=<br />
until [ "$Para" ]<br />
do<br />
clear<br />
read -p &#8220;Título do Álbum: &#8221; Tit<br />
if  [ ! "$Tit" ] # Se titulo vazio&#8230;<br />
then<br />
Para=1     # Liguei flag de saída<br />
else<br />
if grep &#8220;^$Tit^&#8221; musicas &gt; /dev/null<br />
then<br />
echo Este álbum já está cadastrado<br />
exit 1<br />
fi<br />
Reg=&#8221;$Tit^&#8221;<br />
Cont=1<br />
oArt=<br />
while [ "$Tit" ]<br />
do<br />
echo Dados da trilha $Cont:<br />
read -p &#8220;Música: &#8221; Mus<br />
[ "$Mus" ] || break       # Sai se vazio<br />
read -p &#8220;Artista: $oArt // &#8221; Art<br />
[ "$Art" ] &amp;&amp; oArt=&#8221;$Art&#8221; # Se vazio Art anterior<br />
Reg=&#8221;$Reg$oArt~$Mus:&#8221;     # Montando registro<br />
Cont=$((Cont + 1))<br />
# A linha anterior tb poderia ser ((Cont++))<br />
done<br />
echo &#8220;$Reg&#8221; &gt;&gt; musicas<br />
sort musicas -o musicas<br />
fi<br />
done</font></div>
<p>Nesta versão, um <i>loop</i> maior foi adicionado antes da leitura do título, que só terminará quando a variável <code>$Para</code> deixar de ser vazia. Caso o título do álbum não seja informado, a variável <code>$Para</code> receberá valor (no caso coloquei <code>1</code> mas poderia ter colocado qualquer coisa. O importante é que não seja vazia) para sair deste <i>loop</i>, terminando desta forma o programa. No resto, o <i>script</i> é idêntico à sua versão anterior.</p>
<h3><a title="Atalhos_no_loop" name="Atalhos_no_loop"></a> Atalhos no loop</h3>
<p>Nem sempre um ciclo de programa, compreendido entre um <code>do</code> e um <code>done</code>, sai pela porta da frente. Em algumas oportunidades, temos que colocar um comando que aborte de forma controlada este <i>loop</i>. De maneira inversa, algumas vezes desejamos que o fluxo de execução do programa volte antes de chegar ao done. Para isto, temos respectivamente, os comandos <code>break</code> (que já vimos rapidamente nos exemplos do comado <code>while</code>) e <code>continue</code>, que funcionam da seguinte forma:</p>
<p>O que eu não havia dito anteriormente é que nas suas sintaxes genéricas eles aparecem da seguinte forma:</p>
<p><code>break [qtd loop]</code></p>
<p>e</p>
<p><code>continue [qtd loop]</code></p>
<p>Onde <i>qtd loop</i> representa a quantidade dos <i>loops</i> mais internos sobre os quais os comandos irão atuar. Seu valor <i>default</i> é 1.</p>
<p><img src="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/Fluxograma.jpg" alt="Fluxograma" />  Duvido que você nunca tenha deletado um arquivo e logo após deu um tabefe na testa se xingando porque não devia tê-lo removido. Pois é, na décima vez que fiz esta besteira, criei um <i>script</i> para simular uma lixeira, isto é, quando mando remover um (ou vários) arquivo(s), o programa &#8220;finge&#8221; que removeu-o, mas no duro o que fez foi mandá-lo(s) para o diretório <i>/tmp/LoginName_do_usuario</i>. Chamei este programa de <code>erreeme</code> e no <i>/etc/profile</i> coloquei a seguinte linha:</p>
<p><code>alias rm=erreeme</code></p>
<p>O programa era assim:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat erreeme<font color="#ffffff"><br />
#/bin/bash<br />
#<br />
#  Salvando Copia de Arquivo Antes de Remove-lo<br />
#<br />
</font><br />
<font color="#ffffff">if  [ $# -eq 0 ]  #  Tem de ter um ou mais arquivos para remover<br />
then<br />
echo &#8220;Erro -&gt; Uso: erreeme arq [arq] &#8230; [arq]&#8220;<br />
echo &#8221;  O uso de metacaracteres e’ permitido. Ex. erreeme arq*&#8221;<br />
exit 1<br />
fi<br />
</font><br />
<font color="#ffffff">MeuDir=&#8221;/tmp/$LOGNAME&#8221; # Variavel do sist. Contém o nome do usuário.<br />
if  [ ! -d $MeuDir ]   # Se não existir o meu diretório sob o /tmp&#8230;<br />
then<br />
mkdir $MeuDir      # Vou cria-lo<br />
fi<br />
</font><br />
<font color="#ffffff">if  [ ! -w $MeuDir ]   # Se não posso gravar no diretório&#8230;<br />
then<br />
echo Impossivel salvar arquivos em $MeuDir. Mude permissao&#8230;<br />
exit 2<br />
fi<br />
</font><br />
<font color="#ffffff">Erro=0                 # Variavel para indicar o cod. de retorno do prg<br />
for Arq                # For sem o &#8220;in&#8221; recebe os parametros passados<br />
do<br />
if  [ ! -f $Arq ]  # Se este arquivo não existir&#8230;<br />
then<br />
echo $Arq nao existe.<br />
Erro=3<br />
continue       # Volta para o comando for<br />
fi<br />
</font><br />
<font color="#ffffff"> DirOrig=`dirname $Arq` # Cmd. dirname informa nome do dir de $Arq<br />
if  [ ! -w $DirOrig ]  # Verifica permissão de gravacaoo no diretório<br />
then<br />
echo Sem permissao de remover no diretorio de $Arq<br />
Erro=4<br />
continue           # Volta para o comando for<br />
fi<br />
</font><br />
<font color="#ffffff">    if  [ "$DirOrig" = "$MeuDir" ] # Se estou &#8220;esvaziando a lixeira&#8221;&#8230;<br />
then<br />
echo $Arq ficara sem copia de seguranca<br />
rm -i $Arq         # Pergunta antes de remover<br />
[ -f $Arq ] || echo $Arq removido  # Será que o usuario removeu?<br />
continue<br />
fi<br />
</font><br />
<font color="#ffffff">    cd $DirOrig     # Guardo no fim do arquivo o seu diretorio<br />
pwd &gt;&gt; $Arq  # original para usa-lo em um script de undelete<br />
mv $Arq $MeuDir  # Salvo e removo<br />
echo $Arq removido<br />
done<br />
exit $Erro # Passo eventual numero do erro para o codigo de retorno</font></div>
<p>Como você pode ver, a maior parte do <i>script</i> é formada por pequenas criticas aos parâmetros informados, mas como o <i>script</i> pode ter recebido diversos arquivos para remover, a cada arquivo que não se encaixa dentro do especificado, há um <code>continue</code>, para que a sequência volte para o <i>loop</i> do <code>for</code> de forma a receber outros arquivos.</p>
<p>Quando você está no <i>Windows</i> (com perdão da má palavra) e tenta remover aquele monte de lixo com nomes esquisitos como <code>HD04TG.TMP</code>, se der erro em um deles, os outros não são removidos, não é? Então, o <code>continue</code> foi usado para evitar que um impropério desses ocorra, isto é, mesmo que dê erro na remoção de um arquivo, o programa continuará removendo os outros que foram passados.</p>
<p>- Eu acho que a esta altura você deve estar curioso para ver o programa que restaura o arquivo removido, não é? Pois então aí vai vai um desafio: faça-o em casa e me traga para discutirmos no nosso próximo encontro aqui no boteco.</p>
<p>- Poxa, mas nesse eu acho que vou dançar, pois não sei nem como começar&#8230;</p>
<p>- Cara, este programa é como tudo que se faz em Shell, extremamente fácil, é para ser feito em, no máximo 10 linhas. Não se esqueça que o arquivo está salvo em <code>/tmp/$LOGNAME</code> e que a sua última linha é o diretório em que ele residia antes de ser &#8220;removido&#8221;. Também não se esqueça de criticar se foi passado o nome do arquivo a ser removido.</p>
<p>- É eu vou tentar, mas sei não&#8230;</p>
<p>- Tenha fé irmão, eu tô te falando que é mole! Qualquer dúvida é só me passar um e-mail para <a href="mailto:julio.neves@gmail.com?Subject=Duvidas%20Papo%20de%20botequim">julio.neves@gmail.com</a>. Agora chega de papo que eu já estou de goela seca de tanto falar. Me acompanha no próximo chope ou já vai sair correndo para fazer o script que passei?</p>
<p>- Deixa eu pensar um pouco&#8230;</p>
<p>- Chico, traz mais um chope enquanto ele pensa!</p>
<p>Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em <i>Shell</i> que mande um e-mail para a nossa <a href="mailto:treinamentos@festivalsoftwarelivre.org?Subject=Curso%20de%20Shell%20com%20Julio%20Neves">gerencia de treinamento</a> para informar-se.</p>
<p>Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para <a href="mailto:julioneves@openoffice.org?Subject=D%C3%BAvidas%20Papo%20de%20Botequim">mim</a>.</p>
<p>Valeu!</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/jneves.wordpress.com/12/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/jneves.wordpress.com/12/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jneves.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jneves.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jneves.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jneves.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jneves.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jneves.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jneves.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jneves.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jneves.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jneves.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jneves.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jneves.wordpress.com/12/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jneves.wordpress.com/12/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jneves.wordpress.com/12/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=12&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-6/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/53f0649d2d6a9b19b90abd0575ee5c7c?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">jneves</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" medium="image">
			<media:title type="html">Pinguim com placa de dica</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/pinguim_dica.gif" medium="image">
			<media:title type="html">Pinguim com placa de dica</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWikiBar/FreeSkinImagens/Fluxograma.jpg" medium="image">
			<media:title type="html">Fluxograma</media:title>
		</media:content>
	</item>
		<item>
		<title>Papo de Botequim &#8211; Parte 7</title>
		<link>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-7/</link>
		<comments>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-7/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 16:19:29 +0000</pubDate>
		<dc:creator>jneves</dc:creator>
				<category><![CDATA[Shell]]></category>
		<category><![CDATA[xargs]]></category>
		<category><![CDATA[grep]]></category>
		<category><![CDATA[tput]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[while]]></category>
		<category><![CDATA[then]]></category>
		<category><![CDATA[if]]></category>
		<category><![CDATA[$LOGNAME]]></category>
		<category><![CDATA[read]]></category>
		<category><![CDATA[echo]]></category>
		<category><![CDATA[do]]></category>
		<category><![CDATA[seq]]></category>

		<guid isPermaLink="false">http://jneves.wordpress.com/?p=11</guid>
		<description><![CDATA[O comando tput E agora podemos ler os dados da tela Vamos ler arquivos? &#8211; Cumequié rapaz! Derreteu os pensamentos para fazer o scriptizinho que eu te pedi? &#8211; É, eu realmente tive de colocar muita pensação na tela preta mas acho que consegui! Bem, pelo menos no testes que fiz a coisa funcionou, mas [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=11&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div class="twikiToc">
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo007#O_comando_tput"> O comando tput</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo007#E_agora_podemos_ler_os_dados_da"> E agora podemos ler os dados da tela</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo007#Vamos_ler_arquivos"> Vamos ler arquivos?</a></li>
</ul>
</li>
</ul>
</div>
<hr />      &#8211; Cumequié rapaz! Derreteu os pensamentos para fazer o scriptizinho que eu te pedi?      &#8211; É, eu realmente tive de colocar muita pensação na tela preta mas acho que consegui! Bem, pelo menos no testes que fiz a coisa funcionou, mas você tem sempre que botar chifres em cabeça de cachorro!- Não é bem assim, programar em shell é muito fácil, o que vale são as dicas e macetes que não são triviais. As correções que te faço, são justamente para mostrá-los. Mas vamos pedir dois chopes enquanto dou uma olhadela no teu script.- Aê Chico, traz dois. Não esqueça que um é sem colarinho.<br />
<hr />
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat restaura<br />
<font color="#ffffff"><br />
#!/bin/bash<br />
#<br />
# Restaura arquivos deletados via erreeme<br />
#<br />
</font><br />
<font color="#ffffff">if [ $# -eq 0 ]<br />
then<br />
echo &#8220;Uso: $0 &#8220;<br />
exit 1<br />
fi<br />
# Pega nome do diretório original na última linha<br />
Dir=`tail -1 /tmp/$LOGNAME/$1`<br />
# O grep -v exclui última linha e cria o<br />
# arquivo com diretorio e nome originais<br />
grep -v $Dir /tmp/$LOGNAME/$1 &gt; $Dir/$1<br />
# Remove arquivo que jah estava moribundo<br />
rm /tmp/$LOGNAME/$1<br />
</font></div>
<p>- Peraí, deixa ver se entendi. Primeiramente você coloca na variável Dir a última linha do arquivo cujo nome é formado por /tmp/nome do operador ($LOGNAME)/parâmetro passado com nome do arquivo a ser restaurado ($1). Em seguida o grep -v que você montou exclui a linha em que estava o nome do diretório, isto é, sempre a última e manda o restante do arquivo, que seria assim o arquivo já limpo, para o diretório original e depois remove o arquivo da &#8220;lixeira&#8221;; S E N S A C I O N A L! Impecável! Zero erro! Viu? você já está pegando as manhas do shell!</p>
<p>- Então vamulá chega de lesco-lesco e blá-blá-blá, de que você vai falar hoje?</p>
<p>- É tô vendo que o bichinho do Shell te pegou. Que bom, mas vamos ver como se pode (e deve) ler dados e formatar telas e primeiramente vamos entender um comando que te dá todas as ferramentas para você formatar a sua tela de entrada de dados.</p>
<h2><a title="O_comando_tput" name="O_comando_tput"></a> O comando tput</h2>
<p>O maior uso deste comando é para posicionar o cursor na tela, mas também é muito usado para apagar dados da tela, saber a quantidade de linhas e colunas para poder posicionar corretamente um campo, apagar um campo cuja crítica detectou como errado. Enfim, quase toda a formatação da tela é feita por este comando.</p>
<p>Uns poucos atributos do comando <code>tput</code> podem eventualmente não funcionar se o modelo de terminal definido pela variável $TERM não tiver esta facilidade incorporada.</p>
<p>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ó:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ tput it<font color="#ffffff"><br />
8</font></div>
<p>Neste exemplo eu recebi o tamanho inicial da <kbd>&lt;TAB&gt;</kbd> ( <kbd>I</kbd>nitial <kbd>T</kbd> ab), mas me diga: para que eu quero saber isso? Se você quiser saber tudo sobre o comando tput (e olha que é coisa que não acaba mais), veja em: <a href="http://www.cs.utah.edu/dept/old/texinfo/tput/tput.html#SEC4" target="_top">http://www.cs.utah.edu/dept/old/texinfo/tput/tput.html#SEC4</a>.</p>
<table class="twikiTable" border="0" cellpadding="2" cellspacing="1">
<tr>
<th colspan="2" class="twikiFirstCol" align="center" bgcolor="#000000"><b><font color="#ffffff">Principais Opções do Comando tput</font></b></th>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><b>Opções do <code>tput</code> </b></td>
<td bgcolor="#ffffff"><b>Efeito</b></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>cup lin col</code></td>
<td bgcolor="#ffffff"><kbd>CU</kbd>rsor <kbd>P</kbd>osition &#8211; Posiciona o cursor na linha lin e coluna col. A origem é zero</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>bold</code></td>
<td bgcolor="#ffffff">Coloca a tela em modo de ênfase</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>rev</code></td>
<td bgcolor="#ffffff">Coloca a tela em modo de vídeo reverso</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>smso</code></td>
<td bgcolor="#ffffff">Idêntico ao anterior</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>smul</code></td>
<td bgcolor="#ffffff">A partir desta instrução, os caracteres teclados aparecerão sublinhados na tela</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>blink</code></td>
<td bgcolor="#ffffff">Os caracteres teclados aparecerão piscando</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>sgr0</code></td>
<td bgcolor="#ffffff">Após usar um dos atributos acima, use este para restaurar a tela ao seu modo normal</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>reset</code></td>
<td bgcolor="#ffffff">Limpa o terminal e restaura suas definições de acordo com o <code>terminfo</code> ou seja, o terminal volta ao padrão definido pela variável <code>$TERM</code></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>lines</code></td>
<td bgcolor="#ffffff">Devolve a quantidade de linhas da tela no momento da instrução</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>cols</code></td>
<td bgcolor="#ffffff">Devolve a quantidade de colunas da tela no momento da instrução</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>el</code></td>
<td bgcolor="#ffffff"><kbd>E</kbd>rase <kbd>L</kbd>ine &#8211; Apaga a linha a partir da posição do cursor</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>ed</code></td>
<td bgcolor="#ffffff"><kbd>E</kbd>rase <kbd>D</kbd>isplay &#8211; Apaga a tela a partir da posição do cursor</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>il n</code></td>
<td bgcolor="#ffffff"><kbd>I</kbd>nsert <kbd>L</kbd>ines &#8211; Insere <code>n</code> linhas a partir da posição do cursor</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>dl n</code></td>
<td bgcolor="#ffffff"><kbd>D</kbd>elete <kbd>L</kbd>ines &#8211; Remove <code>n</code> linhas a partir da posição do cursor</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>ech n</code></td>
<td bgcolor="#ffffff"><kbd>E</kbd>rase <kbd>CH</kbd>aracters &#8211; Apaga <code>n</code> caracteres a partir da posição do cursor</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>sc</code></td>
<td bgcolor="#ffffff"><kbd>S</kbd>ave <kbd>C</kbd>ursor position &#8211; Salva a posição do cursor</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>rc</code></td>
<td bgcolor="#ffffff"><kbd>R</kbd>estore <kbd>C</kbd>ursor position &#8211; Coloca o cursor na posição marcada pelo último <code>sc</code></td>
</tr>
</table>
<p>Vamos fazer um programa bem besta (e portanto fácil) para mostrar alguns atributos deste comando. É o famoso e famigerado Alô Mundo só que esta frase será escrita no centro da tela e em vídeo reverso e após isso, o cursor voltará para a posição em que estava antes de escrever esta tão criativa frase. Veja:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat alo.sh<font color="#ffffff"><br />
#!/bin/bash<br />
# Script bobo para testar<br />
# o comando tput (versao 1)<br />
</font><br />
<font color="#ffffff">Colunas=`tput cols`     #  Salvando quantidade colunas<br />
Linhas=`tput lines`     #  Salvando quantidade linhas<br />
Linha=$((Linhas / 2))   #  Qual eh a linha do meio da tela?<br />
Coluna=$(((Colunas &#8211; 9) / 2)) # Centrando a mensagem na tela<br />
tput sc                 #  Salvando posicao do cursor<br />
tput cup $Linha $Coluna #  Posicionando para escrever<br />
tput rev                #  Video reverso<br />
echo Alô Mundo<br />
tput sgr0               #  Restaura video ao normal<br />
tput rc                 #  Restaura cursor aa posição original</font></div>
<p>Como o programa já está todo comentado, acho que a única explicação necessária seria para a linha em que é criada a variável <code>Coluna</code> e o estranho ali é aquele número <code>9</code>, mas ele é o tamanho da cadeia que pretendo escrever (Alô Mundo).</p>
<p>Desta forma este programa somente conseguiria centrar cadeias de 9 caracteres, mas veja isso:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ var=Papo<br />
$ echo ${#var}<font color="#ffffff"><br />
4</font><br />
$ var=&#8221;Papo de Botequim&#8221;<br />
$ echo ${#var}<font color="#ffffff"><br />
16</font></div>
<p>Ahhh, melhorou! Então agora sabemos que a construção <code>${#variavel}</code> devolve a quantidade de caracteres de <code>variavel</code>. Assim sendo, vamos otimizar o nosso programa para que ele escreva em vídeo reverso, no centro da tela a cadeia passada como parâmetro e depois o cursor volte à posição que estava antes da execução do script.</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat alo.sh<font color="#ffffff"><br />
#!/bin/bash<br />
# Script bobo para testar<br />
# o comando tput (versao 2)<br />
</font><br />
<font color="#ffffff">Colunas=`tput cols`      #  Salvando quantidade colunas<br />
Linhas=`tput lines`      #  Salvando quantidade linhas<br />
Linha=$((Linhas / 2))    # Qual eh a linha do meio da tela?<br />
Coluna=$(((Colunas &#8211; ${#1}) / 2)) #Centrando a mensagem na tela<br />
tput sc                  # Salvando posicao do cursor<br />
tput cup $Linha $Coluna  #  Posicionando para escrever<br />
tput rev                 #  Video reverso<br />
echo $1<br />
tput sgr0                #  Restaura video ao normal<br />
tput rc                  #  Restaura cursor aa posição original</font></div>
<p>Este script é igual ao anterior, só que trocamos o valor fixo da versão anterior (<code>9</code>), por <code>${#1}</code>, onde este <code>1</code> é o <code>$1</code> ou seja, esta construção devolve o tamanho do primeiro parâmetro passado para o programa. Se o parâmetro que eu quiser passar tiver espaços em branco, teria que colocá-lo todo entre aspas, senão o <code>$1</code> seria somente o primeiro pedaço. Para evitar este aborrecimento, é só substituir o <code>$1</code> por <code>$*</code>, que como sabemos é o conjunto de todos os parâmetros. Então aquela linha ficaria assim:</p>
<pre>    Coluna=`$(((Colunas - ${#*}) / 2))` #Centrando a mensagem na tela</pre>
<p>e a linha <code>echo $1</code> passaria a ser <code>echo $*</code>. Mas não esqueça de qdo executar, passar a frase que vc desja centrar como parâmetro.</p>
<h2><a title="E_agora_podemos_ler_os_dados_da" name="E_agora_podemos_ler_os_dados_da"></a><a title="E_agora_podemos_ler_os_dados_da_" name="E_agora_podemos_ler_os_dados_da_"></a> E agora podemos ler os dados da tela</h2>
<p>Bem a partir de agora vamos aprender tudo sobre leitura, só não posso ensinar a ler cartas e búzios porque se eu soubesse, estaria rico, num <i>pub</i> londrino tomando <i>scotch</i> e não em um boteco desses tomando chope. Mas vamos em frente.</p>
<p>Da última vez que nos encontramos aqui eu já dei uma palinha sobre o comando <code>read</code>. Para começarmos a sua analise mais detalhada. veja só isso:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ read var1 var2 var3<font color="#ffffff"><br />
Papo de Botequim</font><br />
$ echo $var1<font color="#ffffff"><br />
Papo</font><br />
$ echo $var2<font color="#ffffff"><br />
de</font><br />
$ echo $var3<font color="#ffffff"><br />
Botequim</font><br />
$ read var1 var2<font color="#ffffff"><br />
Papo de Botequim</font><br />
$ echo $var1<font color="#ffffff"><br />
Papo</font><br />
$ echo $var2<font color="#ffffff"><br />
de Botequim</font></div>
<p>Como você viu, o <code>read</code> recebe uma lista separada por espaços em branco e coloca cada item desta lista em uma variável. Se a quantidade de variáveis for menor que a quantidade de itens, a última variável recebe o restante.</p>
<p>Eu disse lista separada por espaços em branco? Agora que você já conhece tudo sobre o <code>$IFS</code> (<kbd>I</kbd>nter <kbd>F</kbd>ield <kbd>S</kbd>eparator) que eu te apresentei quando falávamos do comando <code>for</code>, será que ainda acredita nisso? Vamos testar direto no <i>prompt</i>:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ oIFS=&#8221;$IFS&#8221;<br />
$ IFS=:<br />
$ read var1 var2 var3<font color="#ffffff"><br />
Papo de Botequim</font><br />
$ echo $var1<font color="#ffffff"><br />
Papo de Botequim</font><br />
$ echo $var2$ echo $var3<br />
$ read var1 var2 var3<font color="#ffffff"><br />
Papo:de:Botequim</font><br />
$ echo $var1<font color="#ffffff"><br />
Papo</font><br />
$ echo $var2<font color="#ffffff"><br />
de</font><br />
$ echo $var3<font color="#ffffff"><br />
Botequim</font><br />
$ IFS=&#8221;$oIFS&#8221;</div>
<p>Viu, estava furado! O <code>read</code> lê uma lista, assim como o <code>for</code>, separada pelos caracteres da variável <code>$IFS</code>. Então veja como isso pode facilitar a sua vida:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ grep julio /etc/passwd<font color="#ffffff"><br />
julio:x:500:544:Julio C. Neves &#8211; 7070:/home/julio:/bin/bash</font><br />
$ oIFS=&#8221;$IFS&#8221;    #  Salvando IFS<br />
$ IFS=:<br />
$ grep julio /etc/passwd | read lname lixo uid gid coment home shell<br />
$ echo -e &#8220;$lnamen$uidn$gidn$comentn$homen$shell&#8221;<font color="#ffffff"><br />
julio<br />
500<br />
544<br />
Julio C. Neves &#8211; 7070<br />
/home/julio<br />
/bin/bash</font><br />
$ IFS=&#8221;$oIFS&#8221;   #  Restaurando IFS</div>
<p>Como você viu, a saída do <code>grep</code> foi redirecionada para o comando <code>read</code> que leu todos os campos de uma só tacada. A opção <code>-e</code> do <code>echo</code> foi usada para que o <code>n</code> fosse entendido como um salto de linha (<i>new line</i>), e não como um literal.</p>
<p>Sob o Bash existem diversas opções do <code>read</code> que servem para facilitar a sua vida. Veja a tabela a seguir:</p>
<table class="twikiTable" border="0" cellpadding="2" cellspacing="1">
<tr>
<th colspan="2" class="twikiFirstCol" align="center" bgcolor="#000000"><b><font color="#ffffff">Opções do comando read no Bash</font></b></th>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#ffffff"><b>Opção</b></td>
<td bgcolor="#ffffff"><b>Ação</b></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>-p prompt</code></td>
<td bgcolor="#ffffff">Escreve o <code>prompt</code> antes de fazer a leitura</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>-n num</code></td>
<td bgcolor="#ffffff">Lê até <code>num</code> caracteres</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>-t seg</code></td>
<td bgcolor="#ffffff">Espera <code>seg</code> segundos para que a leitura seja concluída</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff"><code>-s</code></td>
<td bgcolor="#ffffff">O que está sendo teclado não aparece na tela</td>
</tr>
</table>
<p>E agora direto aos exemplos curtos para demonstrar estas opções.</p>
<p>Para ler um campo &#8220;Matrícula&#8221;:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo -n &#8220;Matricula: &#8220;; read Mat # -n nao salta linha<font color="#ffffff"><br />
Matricula: 12345</font><br />
$ echo $Mat<font color="#ffffff"><br />
12345</font></div>
<p>Ou simplificando com a opção <code>-p</code>:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ read -p &#8220;Matricula: &#8221; Mat<font color="#ffffff"><br />
Matricula: 12345</font><br />
$ echo $Mat<font color="#ffffff"><br />
12345</font></div>
<p>Para ler uma determinada quantidade de caracteres:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ read -n5 -p&#8221;CEP: &#8221; Num ; read -n3 -p- Compl<font color="#ffffff"><br />
CEP: 12345-678</font>$<br />
$ echo $Num<font color="#ffffff"><br />
12345</font><br />
$ echo $Compl<font color="#ffffff"><br />
678</font></div>
<p>Neste exemplo fizemos dois <code>read</code>: um para a primeira parte do CEP e outra para o seu complemento, deste modo formatando a entrada de dados. O cifrão (<code>$</code>) após o último algarismo teclado, é porque o <code>read</code> não tem o <i>new-line</i> implícito por <i>default</i> como o tem o <code>echo</code>.</p>
<p>Para ler que até um determinado tempo se esgote (conhecido como <i>time out</i>):</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ read -t2 -p &#8220;Digite seu nome completo: &#8221; Nom || echo &#8216;Eta moleza!&#8217;<font color="#ffffff"><br />
Digite seu nome completo: JEta moleza!</font><br />
$ echo $Nom$</div>
<p>Obviamente isto foi uma brincadeira, pois só tinha 3 segundos para digitar o meu nome completo e só me deu tempo de teclar um <code>J</code> (aquele colado no <code>Eta</code>), mas serviu para mostrar duas coisas:</p>
<ol>
<li> O comando após o par de barras verticais (<code>||</code>) (o ou lógico, lembra-se?) será executado caso a digitação não tenha sido concluída no tempo estipulado;</li>
<li> A variável <code>Nom</code> permaneceu vazia. Ela será valorada somente quando o <code>&lt;ENTER&gt;</code> for teclado.</li>
</ol>
<p>Para ler um dado sem ser exibido na tela:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ read -sp &#8220;Senha: &#8220;<font color="#ffffff"><br />
Senha: </font>$ echo $REPLY<font color="#ffffff"><br />
segredo <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> </font></div>
<p>Aproveitei um erro para mostrar um macete. Quando escrevi a primeira linha, esqueci de colocar o nome da variável que iria receber a senha, e só notei quando ia listar o seu valor. Felizmente a variável <code>$REPLY</code> do Bash, possui a última cadeia lida e me aproveitei disso para não perder a viagem. Teste você mesmo o que acabei de fazer.</p>
<p>Mas o exemplo que dei, era para mostrar que a opção <code>-s</code> impede o que está sendo teclado de ir para a tela. Como no exemplo anterior, a falta do <i>new-line</i> fez com que o <i>prompt</i> de comando (<code>$</code>) permanecesse na mesma linha.</p>
<p>Bem, agora que sabemos ler da tela vejamos como se lê os dados dos arquivos.</p>
<h3><a title="Vamos_ler_arquivos" name="Vamos_ler_arquivos"></a><a title="Vamos_ler_arquivos_" name="Vamos_ler_arquivos_"></a> Vamos ler arquivos?</h3>
<p>Como eu já havia lhe dito, e você deve se lembrar, o <code>while</code> testa um comando e executa um bloco de instruções enquanto este comando for bem sucedido. Ora quando você está lendo um arquivo que lhe dá permissão de leitura, o <code>read</code> só será mal sucedido quando alcançar o <code>EOF</code> (<i>end of file</i>), desta forma podemos ler um arquivo de duas maneiras:</p>
<p>1 &#8211; Redirecionando a entrada do arquivo para o bloco do <code>while</code> assim:</p>
<pre>    while read Linha
    do
        echo $Linha
    done &lt; arquivo</pre>
<p>2 &#8211; Redirecionando a saída de um <code>cat</code> para o <code>while</code>, da seguinte maneira:</p>
<pre>    cat arquivo |
    while read Linha
    do
        echo $Linha
    done</pre>
<p>Cada um dos processos tem suas vantagens e desvantagens:</p>
<p>Vantagens do primeiro processo:</p>
<ul>
<li> É mais rápido;</li>
<li> Não necessita de um <i>subshell</i> para assisti-lo;</li>
</ul>
<p>Desvantagem do primeiro processo:</p>
<ul>
<li> Em um bloco de instruções grande, o redirecionamento fica pouco visível o que por vezes prejudica a vizualização do código;</li>
</ul>
<p>Vantagem do segundo processo:</p>
<ul>
<li> Como o nome do arquivo está antes do <code>while</code>, é mais fácil a vizualização do código.</li>
</ul>
<p>Desvantagens do segundo processo:</p>
<ul>
<li> O <i>Pipe</i> (<code>|</code>) chama um <i>subshell</i> para interpretá-lo, tornando o processo mais lento, pesado e por vezes problemático (veja o exemplo a seguir).</li>
</ul>
<p>Para ilustrar o que foi dito, veja estes exemplos a seguir:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat readpipe.sh<font color="#ffffff"><br />
#!/bin/bash<br />
# readpipe.sh<br />
# Exemplo de read passando arquivo por pipe.<br />
</font><br />
<font color="#ffffff">Ultimo=&#8221;(vazio)&#8221;<br />
cat $0 | # Passando o arq. do script ($0) p/ while<br />
while read Linha<br />
do<br />
Ultimo=&#8221;$Linha&#8221;<br />
echo &#8220;-$Ultimo-&#8221;<br />
done<br />
echo &#8220;Acabou, Último=:$Ultimo:&#8221;</font></div>
<p>Vamos ver sua execução:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ readpipe.sh<font color="#ffffff"><br />
-#!/bin/bash-<br />
-# readpipe.sh-<br />
-# Exemplo de read passando arquivo por pipe.-<br />
&#8211;<br />
-Ultimo=&#8221;(vazio)&#8221;-<br />
-cat $0 | # Passando o arq. do script ($0) p/ while-<br />
-while read Linha-<br />
-do-<br />
-Ultimo=&#8221;$Linha&#8221;-<br />
-echo &#8220;-$Ultimo-&#8221;-<br />
-done-<br />
-echo &#8220;Acabou, Último=:$Ultimo:&#8221;-<br />
Acabou, Último=:(vazio):</font></div>
<p>Como você viu, o <i>script</i> lista todas as suas próprias linhas com um sinal de menos (<code>-</code>) antes e outro depois de cada, e no final exibe o conteúdo da variável <code>$Ultimo</code>. Repare no entanto que o conteúdo desta variável permanece como <code>(vazio)</code>.</p>
<p>- Ué será que a variável não foi atualizada?</p>
<p>- Foi, e isso pode ser comprovado porque a linha <code>echo "-$Ultimo-"</code> lista corretamente as linhas.</p>
<p>- Então porque isso aconteceu?</p>
<p>- Por que como eu disse, o bloco de instruções redirecionado pelo <i>pipe</i> (<code>|</code>) é executado em um <i>subshell</i> e lá as variáveis são atualizadas. Quando este <i>subshell</i> termina, as atualizações das variáveis vão para os píncaros do inferno junto com ele. Repare que vou fazer uma pequena mudança nele, passando o arquivo por redirecionamento de entrada (&lt;) e as coisas passarão a funcionar na mais perfeita ordem:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat redirread.sh<font color="#ffffff"><br />
#!/bin/bash<br />
# redirread.sh<br />
# Exemplo de read passando arquivo por pipe.<br />
</font><br />
<font color="#ffffff">Ultimo=&#8221;(vazio)&#8221;<br />
while read Linha<br />
do<br />
Ultimo=&#8221;$Linha&#8221;<br />
echo &#8220;-$Ultimo-&#8221;<br />
done &lt; $0 # Passando o arq. do script ($0) p/ while<br />
echo &#8220;Acabou, Último=:$Ultimo:&#8221;</font></div>
<p>E veja a sua perfeita execução:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ redirread.sh<font color="#ffffff"><br />
-#!/bin/bash-<br />
-# redirread.sh-<br />
-# Exemplo de read passando arquivo por pipe.-<br />
&#8211;<br />
-Ultimo=&#8221;(vazio)&#8221;-<br />
-while read Linha-<br />
-do-<br />
-Ultimo=&#8221;$Linha&#8221;-<br />
-echo &#8220;-$Ultimo-&#8221;-<br />
-done &lt; $0 # Passando o arq. do script ($0) p/ while-<br />
-echo &#8220;Acabou, Último=:$Ultimo:&#8221;-<br />
Acabou, Último=:echo &#8220;Acabou, Último=:$Ultimo:&#8221;:</font></div>
<p>Bem amigos da Rede <i>Shell</i>, para finalizar o comando <code>read</code> só falta mais um pequeno e importante macete que vou mostrar utilizando um exemplo prático. Suponha que você queira listar na tela um arquivo e a cada dez registros esta listagem pararia para que o operador pudesse ler o conteúdo da tela e ela só voltasse a rolar (<i>scroll</i>) após o operador digitar qualquer tecla. Para não gastar papel (da Linux Magazine) pra chuchu, vou fazer esta listagem na horizontal e o meu arquivo (<code>numeros</code>), tem 30 registros somente com números seqüênciais. Veja:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ seq 30 | xargs -i echo lin {} &gt; numeros   #  Criando arquivo numeros<br />
$ paste -sd&#8217;:&#8217; numeros                      #  Este paste é para exibir o conteúdo sem ser um<br />
#+ por linha, usando dois-pontos como separador<font color="#ffffff"><br />
lin 1:lin 2:lin 3:lin 4:lin 5:lin 6:lin 7:lin 8:lin 9:lin 10:lin 11:lin 12:lin 13:lin 14:lin 15:l<br />
in 16:lin 17:lin 18:lin 19:lin 20:lin 21:lin 22:lin 23:lin 24:lin 25:lin 26:lin 27:lin 28:lin 29:<br />
lin 30</font><br />
$ cat 10porpag.sh<font color="#ffffff"><br />
#!/bin/bash<br />
# Prg de teste para escrever<br />
# 10 linhas e parar para ler<br />
# Versão 1<br />
</font><br />
<font color="#ffffff">while read Num<br />
do<br />
let ContLin++           # Contando&#8230;<br />
echo -n &#8220;$Num &#8221;         # -n para nao saltar linha<br />
((ContLin % 10)) &gt; /dev/null || read<br />
done &lt; numeros</font></div>
<p>Na tentativa de fazer um programa genérico criamos a variável <code>$ContLin</code> (por que na vida real, os registros não são somente números seqüenciais) e parávamos para ler quando o resto da divisão por <code>10</code> fosse zero (mandando a saída para <code>/dev/null</code> de forma a não aparecer na tela, sujando-a). Porém, quando fui executar deu a seguinte zebra:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ 10porpag.sh<font color="#ffffff"><br />
lin 1 lin 2 lin 3 lin 4 lin 5 lin 6 lin 7 lin 8 lin 9 lin 10 lin 12 lin 13 lin 14 lin 15 lin 16 l<br />
in 17 lin 18 lin 19 lin 20 lin 21 lin 23 lin 24 lin 25 lin 26 lin 27 lin 28 lin 29 lin 30 </font>$</div>
<p>Repare que faltou a linha <code>lin 11</code> e a listagem não parou no <code>read</code>. O que houve foi que toda a entrada do <i>loop</i> estava redirecionada do arquivo <code>numeros</code> e desta forma, a leitura foi feita em cima deste arquivo, desta forma perdendo a <code>lin 11</code> (e também a <code>lin 22</code> ou qualquer linha múltipla de 11).</p>
<p>Vamos mostrar então como deveria ficar para funcionar a contento:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat 10porpag.sh<font color="#ffffff"><br />
#!/bin/bash<br />
# Prg de teste para escrever<br />
# 10 linhas e parar para ler<br />
# Versão 2<br />
</font><br />
<font color="#ffffff">while read Num<br />
do<br />
let ContLin++           # Contando&#8230;<br />
echo -n &#8220;$Num &#8221;         # -n para nao saltar linha<br />
((ContLin % 10)) &gt; /dev/null || read &lt; /dev/tty<br />
done &lt; numeros</font></div>
<p>Observe que agora a entrada do <code>read</code> foi redirecionada por <code>/dev/tty</code>, que nada mais é senão o terminal corrente, explicitando desta forma que aquela leitura seria feita do teclado e não de numeros. É bom realçar que isto não acontece somente quando usamos o redirecionamento de entrada, se houvéssemos usado o redirecionamento via <i>pipe</i> (<code>|</code>), o mesmo teria ocorrido.</p>
<p>Veja agora a sua execução:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ 10porpag.sh<font color="#ffffff"><br />
lin 1 lin 2 lin 3 lin 4 lin 5 lin 6 lin 7 lin 8 lin 9 lin 10<br />
lin 11 lin 12 lin 13 lin 14 lin 15 lin 16 lin 17 lin 18 lin 19 lin 20<br />
lin 21 lin 22 lin 23 lin 24 lin 25 lin 26 lin 27 lin 28 lin 29 lin 30</font></div>
<p>Isto está quase bom mas falta um pouco para ficar excelente. Vamos melhorar um pouco o exemplo para que você o reproduza e teste (mas antes de testar aumente o número de registros de <code>numeros</code> ou reduza o tamanho da tela, para que haja quebra).</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat 10porpag.sh<font color="#ffffff"><br />
#!/bin/bash<br />
# Prg de teste para escrever<br />
# 10 linhas e parar para ler<br />
# Versão 3<br />
</font><br />
<font color="#ffffff">clear<br />
while read Num<br />
do<br />
((ContLin++))                           # Contando&#8230;<br />
echo &#8220;$Num&#8221;<br />
((ContLin % (`tput lines` &#8211; 3))) ||<br />
{<br />
read -n1 -p&#8221;Tecle Algo &#8221; &lt; /dev/tty # para ler qq caractere<br />
clear                               # limpa a tela apos leitura<br />
}<br />
done &lt; numeros</font></div>
<p>A mudança substancial feita neste exemplo é com relação à quebra de página, já que ela é feita a cada quantidade-de-linhas-da-tela (<code>tput lines</code>) menos (<code>-</code>) <code>3</code>, isto é, se a tela tem 25 linha, listará 22 registros e parará para leitura. No comando <code>read</code> também foi feita uma alteração, inserido um <code>-n1</code> para ler somente um caractere sem ser necessariamente um <code>&lt;ENTER&gt;</code> e a opção <code>-p</code> para dar a mensagem.</p>
<p>- Bem meu amigo, por hoje é só porque acho que você já está de saco cheio&#8230;</p>
<p>- Num tô não, pode continuar&#8230;</p>
<p>- Se você não estiver eu estou&#8230; Mas já que você está tão empolgado com o Shell, vou te deixar um exercício 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 <code>echo</code> e depois vá posicionando à frente de cada campo para receber os valores que serão teclados pelo operador.</p>
<p>Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em <i>Shell</i> que mande um e-mail para a nossa <a href="mailto:treinamentos@festivalsoftwarelivre.org?Subject=Curso%20de%20Shell%20com%20Julio%20Neves">gerencia de treinamento</a> para informar-se.</p>
<p>Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para <a href="mailto:julioneves@openoffice.org?Subject=D%C3%BAvidas%20Papo%20de%20Botequim">mim</a>.</p>
<p>Valeu!</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/jneves.wordpress.com/11/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/jneves.wordpress.com/11/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jneves.wordpress.com/11/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jneves.wordpress.com/11/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jneves.wordpress.com/11/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jneves.wordpress.com/11/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jneves.wordpress.com/11/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jneves.wordpress.com/11/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jneves.wordpress.com/11/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jneves.wordpress.com/11/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jneves.wordpress.com/11/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jneves.wordpress.com/11/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jneves.wordpress.com/11/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jneves.wordpress.com/11/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jneves.wordpress.com/11/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jneves.wordpress.com/11/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=11&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-7/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/53f0649d2d6a9b19b90abd0575ee5c7c?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">jneves</media:title>
		</media:content>
	</item>
		<item>
		<title>Papo de Botequim &#8211; Parte 8</title>
		<link>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-8/</link>
		<comments>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-8/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 16:14:39 +0000</pubDate>
		<dc:creator>jneves</dc:creator>
				<category><![CDATA[Shell]]></category>
		<category><![CDATA[cat]]></category>
		<category><![CDATA[exit]]></category>
		<category><![CDATA[function]]></category>
		<category><![CDATA[grep]]></category>
		<category><![CDATA[sort]]></category>
		<category><![CDATA[source]]></category>
		<category><![CDATA[tput]]></category>
		<category><![CDATA[while]]></category>

		<guid isPermaLink="false">http://jneves.wordpress.com/?p=10</guid>
		<description><![CDATA[Funções O comando source &#8211; E aê cara tudo bem? &#8211; Legal!, eu queria te mostrar o que fiz mas já sei que você vai querer molhar o bico primeiro né?- Só pra contrariar, hoje vou deixar você mostrar logo o seu &#8220;bacalho&#8221;. Vai mostra aí o que você fez.- Poxa o exercício que você [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=10&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div class="twikiToc">
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo008#Fun%C3%A7%C3%B5es"> Funções</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo008#O_comando_source"> O comando source</a></li>
</ul>
</div>
<hr />      &#8211; E aê cara tudo bem?      &#8211; Legal!, eu queria te mostrar o que fiz mas já sei que você vai querer molhar o bico primeiro né?- Só pra contrariar, hoje vou deixar você mostrar logo o seu &#8220;bacalho&#8221;. Vai mostra aí o que você fez.- Poxa o exercício que você passou é muito grande. Veja só como eu resolvi:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat musinc5<font color="#ffffff"><br />
#!/bin/bash<br />
# Cadastra CDs (versao 5)<br />
#<br />
clear<br />
LinhaMesg=$((`tput lines` &#8211; 3)) # Linha que msgs serão dadas para operador<br />
TotCols=$(tput cols)            # Qtd colunas da tela para enquadrar msgs<br />
echo &#8220;<br />
Inclusao de Músicas<br />
======== == =======</font><font color="#ffffff">Título do Álbum:<br />
| Este campo foi<br />
Faixa:               &lt;  criado somente para<br />
| orientar o preenchimento<br />
Nome da Música:</font><font color="#ffffff">Intérprete:&#8221;             # Tela montada com um único echo<br />
while true<br />
do<br />
tput cup 5 38; tput el    # Posiciona e limpa linha<br />
read Album<br />
[ ! "$Album" ] &amp;&amp;         # Operador deu &lt;ENTER&gt;<br />
{<br />
Msg=&#8221;Deseja Terminar? (S/n)&#8221;<br />
TamMsg=${#Msg}<br />
Col=$(((TotCols &#8211; TamMsg) / 2))        # Centra msg na linha<br />
tput cup $LinhaMesg $Col<br />
echo &#8220;$Msg&#8221;<br />
tput cup $LinhaMesg $((Col + TamMsg + 1))<br />
read -n1 SN<br />
tput cup $LinhaMesg $Col; tput el      # Apaga msg da tela<br />
[ $SN = "N" -o $SN = "n" ] &amp;&amp; continue # $SN é igual a N ou (-o) n?<br />
clear; exit                            # Fim da execução<br />
}<br />
grep &#8220;^$Album^&#8221; musicas &gt; /dev/null &amp;&amp;<br />
{<br />
Msg=&#8221;Este álbum já está cadastrado&#8221;<br />
TamMsg=${#Msg}<br />
Col=$(((TotCols &#8211; TamMsg) / 2))       # Centra msg na linha<br />
tput cup $LinhaMesg $Col<br />
echo &#8220;$Msg&#8221;<br />
read -n1<br />
tput cup $LinhaMesg $Col; tput el     # Apaga msg da tela<br />
continue                              # Volta para ler outro álbum<br />
}<br />
Reg=&#8221;$Album^&#8221;                      # $Reg receberá os dados para gravação<br />
oArtista=                          # Variavel que guarda artista anterior<br />
while true<br />
do<br />
((Faixa++))<br />
tput cup 7 38<br />
echo $Faixa<br />
tput cup 9 38                  # Posiciona para ler musica<br />
read Musica<br />
[ "$Musica" ] ||               # Se o operador tiver dado &#8230;<br />
{<br />
Msg=&#8221;Fim de Álbum? (S/n)&#8221;<br />
TamMsg=${#Msg}<br />
Col=$(((TotCols &#8211; TamMsg) / 2))       # Centra msg na linha<br />
tput cup $LinhaMesg $Col<br />
echo &#8220;$Msg&#8221;<br />
tput cup $LinhaMesg $((Col + TamMsg + 1)<br />
read -n1 SN<br />
tput cup $LinhaMesg $Col; tput el    # Apaga msg da tela<br />
[ "$SN" = N -o "$SN" = n ]&amp;&amp;continue # $SN é igual a N ou (-o) n?<br />
break                                # Sai do loop para gravar<br />
}<br />
tput cup 11 38                           # Posiciona para ler Artista<br />
[ "$oArtista" ]&amp;&amp; echo -n &#8220;($oArtista) &#8221; # Artista anterior é default<br />
read Artista<br />
[ "$Artista" ] &amp;&amp; oArtista=&#8221;$Artista&#8221;<br />
Reg=&#8221;$Reg$oArtista~$Musica:&#8221;          # Montando registro<br />
tput cup 9 38; tput el                # Apaga Musica da tela<br />
tput cup 11 38; tput el               # Apaga Artista da tela<br />
done<br />
echo &#8220;$Reg&#8221; &gt;&gt; musicas                    # Grava registro no fim do arquivo<br />
sort musicas -0 musicas                   # Classifica o arquivo<br />
done</font></div>
<p>- É o programa tá legal, tá todo estruturadinho, mas gostaria de alguns poucos comentários sobre o que você fez:</p>
<ul>
<li> Só para relembrar, as seguintes construções: <code>[ ! $Album ] &amp;&amp;</code> e <code>[ $Musica ] ||</code> representam a mesma coisa, isto é, no caso da primeira, o testamos se a variável <code>$Album</code> não (<code>!</code>) tem nada dentro, então (<code>&amp;&amp;</code>) &#8230; Na segunda, testamos se <code>$Musica</code> tem dado, senão (<code>||</code>) &#8230;</li>
<li> Se você reclamou do tamanho dele, é porque ainda não dei algumas dicas. Repare que a maior parte do <i>script</i> é para dar mensagens centradas na penúltima linha da tela. Repare ainda que algumas mensagens pedem um S ou um N e outras são só de advertência. Seria o caso típico do uso de funções, que seriam escritas somente uma vez e chamada a execução de diversos pontos do <i>script</i>. Vou montar duas funções para resolver estes casos e vamos incorporá-las ao seu programa para ver o resultado final.</li>
</ul>
<h2><a title="Funções" name="Funções"></a> Funções</h2>
<p>- Chico! Agora traz dois chopes, sendo um sem colarinho, para me dar inspiração.</p>
<pre>    Pergunta ()
        {
        #  A função recebe 3 parâmetros 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 ] &amp;&amp; SN=$2                     # Se vazia coloca default em SN
        echo $SN | tr A-Z a-z                  # A saída de SN será em minúscula
        tput cup $LinhaMesg $Col; tput el      # Apaga msg da tela
        return                                 # Sai da função
        }</pre>
<p>Como podemos ver, uma função é definida quando fazemos <code>nome_da_função ()</code> e todo o seu corpo está entre chaves (<code>{}</code>). Assim como conversamos aqui no Boteco sobre passagem de parâmetros, as funções os recebem da mesma forma, isto é, são parâmetros posicionais (<code>$1, $2, ..., $n</code>) e todas as regras que se aplicam a passagem de parâmetros para programas, também valem para funções, mas é muito importante realçar que os parâmetros passados para um programa não se confundem com aqueles que este passou para suas funções. Isso significa, por exemplo, que o <code>$1</code> de um <i>script</i> é diferente do <code>$1</code> de uma de suas funções</p>
<p>Repare que as variáveis <code>$Msg</code>, <code>$TamMsg</code> e <code>$Col</code> são de uso restrito desta rotina, e por isso foram criadas como <code>local</code>. A finalidade disso é simplesmente para economizar memória, já que ao sair da rotina, elas serão devidamente detonadas da partição e caso não tivesse usado este artifício, permaneceriam residentes.</p>
<p>A linha de código que cria <code>local Msg</code>, concatena ao texto recebido (<code>$1</code>) um abre parênteses, a resposta <i>default</i> (<code>$2</code>) em caixa alta, uma barra, a outra resposta (<code>$3</code>) em caixa baixa e finaliza fechando o parênteses. Uso esta convenção para, ao mesmo tempo, mostrar as opções disponíveis e realçar a resposta oferecida como <i>default</i>.</p>
<p>Quase ao fim da rotina, a resposta recebida (<code>$SN</code>) é passada para caixa baixa de forma que no corpo do programa não se precise fazer este teste.</p>
<p>Veja agora como ficaria a função para dar uma mensagem na tela:</p>
<pre>    function MandaMsg
        {
        # A função recebe somente um parâmetro
        # com a mensagem que se deseja exibir,
        # para não obrigar ao programador passar
        # a msq entre aspas, usaremos $* (todos
        # os parâmetro, lembra?) e não $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 função
        }</pre>
<p>Esta é uma outra forma de definir uma função: não a chamamos como no exemplo anterior usando uma construção com a sintaxe <code>nome_da_função ()</code>, mas sim como <code>function nome_da_função</code>. Quanto ao mais, nada difere da anterior, exceto que, como consta dos comentários, usamos a variável <code>$*</code> que como já sabemos é o conjunto de todos os parâmetros passados, para que o programador não precise usar aspas envolvendo a mensagem que deseja passar para a função.</p>
<p>Para terminar com este blá-blá-blá vamos ver então as alterações que o programa necessita quando usamos o conceito de funções:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat musinc6<font color="#ffffff"><br />
#!/bin/bash<br />
# Cadastra CDs (versao 6)<br />
#<br />
</font><br />
<font color="#ffffff"># Área de variáveis globais<br />
LinhaMesg=$((`tput lines` &#8211; 3))  # Linha que msgs serão dadas para operador<br />
TotCols=$(tput cols)             # Qtd colunas da tela para enquadrar msgs<br />
</font><br />
<font color="#ffffff"># Área de funções<br />
Pergunta ()<br />
{<br />
#  A função recebe 3 parâmetros na seguinte ordem:<br />
#  $1 &#8211; Mensagem a ser dada na tela<br />
#  $2 &#8211; Valor a ser aceito com resposta default<br />
#  $3 &#8211; O outro valor aceito<br />
#  Supondo que $1=Aceita?, $2=s e $3=n, a linha<br />
#  abaixo colocaria em Msg o valor &#8220;Aceita? (S/n)&#8221;<br />
local Msg=&#8221;$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)&#8221;<br />
local TamMsg=${#Msg}<br />
local Col=$(((TotCols &#8211; TamMsg) / 2))        # Centra msg na linha<br />
tput cup $LinhaMesg $Col<br />
echo &#8220;$Msg&#8221;<br />
tput cup $LinhaMesg $((Col + TamMsg + 1))<br />
read -n1 SN<br />
[ ! $SN ] &amp;&amp; SN=$2                     # Se vazia coloca default em SN<br />
echo $SN | tr A-Z a-z                  # A saída de SN será em minúscula<br />
tput cup $LinhaMesg $Col; tput el      # Apaga msg da tela<br />
return                                 # Sai da função<br />
}<br />
function MandaMsg<br />
{<br />
# A função recebe somente um parâmetro<br />
# com a mensagem que se deseja exibir,<br />
# para não obrigar ao programador passar<br />
# a msq entre aspas, usaremos $* (todos<br />
# os parâmetro, lembra?) e não $1.<br />
local Msg=&#8221;$*&#8221;<br />
local TamMsg=${#Msg}<br />
local Col=$(((TotCols &#8211; TamMsg) / 2)) # Centra msg na linha<br />
tput cup $LinhaMesg $Col<br />
echo &#8220;$Msg&#8221;<br />
read -n1<br />
tput cup $LinhaMesg $Col; tput el     # Apaga msg da tela<br />
return                                # Sai da função<br />
}<br />
</font><br />
<font color="#ffffff"># O corpo do programa propriamente dito começa aqui<br />
clear<br />
echo &#8220;<br />
Inclusao de Músicas<br />
======== == =======</font><font color="#ffffff">Título do Álbum:<br />
| Este campo foi<br />
Faixa:               &lt;  criado somente para<br />
| orientar o preenchimento<br />
Nome da Música:</font><font color="#ffffff">Intérprete:&#8221;          # Tela montada com um único echo<br />
while true<br />
do<br />
tput cup 5 38; tput el                 # Posiciona e limpa linha<br />
read Album<br />
[ ! "$Album" ] &amp;&amp;                      # Operador deu<br />
{<br />
Pergunta &#8220;Deseja Terminar&#8221; s n<br />
[ $SN = "n" ] &amp;&amp; continue          # Agora só testo a caixa baixa<br />
clear; exit                        # Fim da execução<br />
}<br />
grep -iq &#8220;^$Album^&#8221; musicas 2&gt; /dev/null &amp;&amp;<br />
{<br />
MandaMsg Este álbum já está cadastrado<br />
continue                        # Volta para ler outro álbum<br />
}<br />
Reg=&#8221;$Album^&#8221;                       # $Reg receberá os dados de gravação<br />
oArtista=                           # Guardará artista anterior<br />
while true<br />
do<br />
((Faixa++))<br />
tput cup 7 38<br />
echo $Faixa<br />
tput cup 9 38                   # Posiciona para ler musica<br />
read Musica<br />
[ "$Musica" ] ||                # Se o operador tiver dado &#8230;<br />
{<br />
Pergunta &#8220;Fim de Álbum?&#8221; s n<br />
[ "$SN" = n ] &amp;&amp; continue      # Agora só testo a caixa baixa<br />
break                          # Sai do loop para gravar dados<br />
}<br />
tput cup 11 38                           # Posiciona para ler Artista<br />
[ "$oArtista" ]&amp;&amp; echo -n &#8220;($oArtista) &#8221; # Artista anterior é default<br />
read Artista<br />
[ "$Artista" ] &amp;&amp; oArtista=&#8221;$Artista&#8221;<br />
Reg=&#8221;$Reg$oArtista~$Musica:&#8221;               # Montando registro<br />
tput cup 9 38; tput el                     # Apaga Musica da tela<br />
tput cup 11 38; tput el                    # Apaga Artista da tela<br />
done<br />
echo &#8220;$Reg&#8221; &gt;&gt; musicas                 # Grava registro no fim do arquivo<br />
sort musicas -o musicas                # Classifica o arquivo<br />
done</font></div>
<p>Repare que a estruturação do <i>script</i> está conforme o gráfico a seguir:</p>
<table class="twikiTable" border="0" cellpadding="2" cellspacing="1">
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff">Variáveis Globais</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff">Funções</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#ffffff">Corpo do Programa</td>
</tr>
</table>
<p>Esta estruturação é devido ao <i>Shell</i> ser uma linguagem interpretada e desta forma o programa é lido da esquerda para a direita e de cima para baixo e uma variável para ser vista simultaneamente pelo <i>script</i> <b>e</b> suas funções deve ser declarada (ou inicializada) antes de qualquer coisa. As funções 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 <i>Shell</i> já o havia antes localizado e registrado que era uma função.</p>
<p>Uma coisa bacana no uso de funções é fazê-las o mais genérico possível de forma que elas sirvam para outras aplicações, sem necessidade de serem reescritas. Essas duas que acabamos de ver têm uso generalizado, pois é difícil um <i>script</i> que tenha uma entrada de dados pelo teclado que não use uma rotina  do tipo da <code>MandaMsg</code> ou não interage com o operador por algo semelhante à <code>Pergunta</code>.</p>
<p>Conselho de amigo: crie um arquivo e cada função nova que você criar, anexe-a a este arquivo. Ao final de um tempo você terá uma bela biblioteca de funções que lhe poupará muito tempo de programação.</p>
<h2><a title="O_comando_source" name="O_comando_source"></a> O comando source</h2>
<p>Vê se você nota algo de diferente na saída do <code>ls</code> a seguir:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ ls -la .bash_profile<font color="#ffffff"><br />
-rw-r&#8211;r&#8211;  1 Julio  unknown   4511 Mar 18 17:45 .bash_profile</font></div>
<p>Não olhe a resposta não, volte a prestar atenção! Bem, já que você está mesmo sem saco de pensar e prefere ler a resposta, vou te dar uma dica: acho que você sabe que o .bash_profile é um dos programas que são automaticamente &#8220;executados&#8221; quando você se loga (ARRGGHH! Odeio este termo). Agora que te dei esta dica olhe novamente para a saída do <code>ls</code> e me diga o que há de diferente nela.</p>
<p>Como eu disse o .bash_profile é &#8220;executado&#8221; em tempo de logon e repare que não tem nenhum direito de execução. Isso se dá porque o se você o executasse como qualquer outro <i>script</i> careta, quando terminasse sua execução todo o ambiente por ele gerado morreria junto com o <i>Shell</i> sob o qual ele foi executado (você se lembra que todos os <i>scripts</i> são executados em <i>subshells</i>, né?).</p>
<p>Pois é. É para coisas assim que existe o comando <code>source</code>, também conhecido por <code>.</code> (ponto). Este comando faz com que não seja criado um novo <i>Shell</i> (um <i>subshell</i>) para executar o programa que que lhe é passado como parâmetro.</p>
<p>Melhor um exemplo que 453 palavras. Veja este <i>scriptizinho</i> a seguir:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat script_bobo<font color="#ffffff"><br />
cd ..<br />
ls</font></div>
<p>Ele simplesmente deveria ir para o diretório acima do diretório atual. Vamos executar uns comandos envolvendo o script_bobo e vamos analisar os resultados:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ pwd<font color="#ffffff"><br />
/home/jneves</font><br />
$ script_bobo<font color="#ffffff"><br />
jneves    juliana   paula     silvie</font><br />
$ pwd<font color="#ffffff"><br />
/home/jneves</font></div>
<p>Se eu mandei ele subir um diretório, porque não subiu? Subiu sim! O <i>subshell</i> que foi criado para executar o <i>script</i> tanto subiu que listou os diretórios dos quatro usuários abaixo do <code>/home</code>, só que assim que o <i>script</i> acabou, o <i>subshell</i> foi para o beleleu e com ele todo o ambiente criado. Olha agora como a coisa muda:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ source script_bobo<font color="#ffffff"><br />
jneves    juliana   paula     silvie</font><br />
$ pwd<font color="#ffffff"><br />
/home</font><br />
$ cd -<font color="#ffffff"><br />
/home/jneves</font><br />
$ . script_bobo<font color="#ffffff"><br />
jneves    juliana   paula     silvie</font><br />
$ pwd<font color="#ffffff"><br />
/home</font></div>
<p>Ahh! Agora sim! Sendo passado como parâmetro do comando <code>source</code> ou <code>.</code> (ponto), o <i>script</i> foi executado no <i>Shell</i> corrente deixando neste, todo o ambiente criado. Agora damos um <i>rewind</i> para o início da explicação sobre este comando. Lá falamos do .bash_profile, e a esta altura você já deve saber que a sua incumbência é, logo após o <i>login</i>, deixar o ambiente de trabalho preparado para o usuário, e agora entendemos que é por isso mesmo que ele é executado usando este artifício.</p>
<p>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 funções como rotinas externas. Veja uma outra forma de fazer o nosso programa para incluir CDs no arquivo <code>musicas</code>:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat musinc7<font color="#ffffff"><br />
#!/bin/bash<br />
# Cadastra CDs (versao 7)<br />
#<br />
</font><br />
<font color="#ffffff"># Área de variáveis globais<br />
LinhaMesg=$((`tput lines` &#8211; 3))  # Linha que msgs serão dadas para operador<br />
TotCols=$(tput cols)             # Qtd colunas da tela para enquadrar msgs<br />
</font><br />
<font color="#ffffff"># O corpo do programa propriamente dito começa aqui<br />
clear<br />
echo &#8220;<br />
Inclusao de Músicas<br />
======== == =======</font><font color="#ffffff">Título do Álbum:<br />
| Este campo foi<br />
Faixa:               &lt;  criado somente para<br />
| orientar o preenchimento<br />
Nome da Música:</font><font color="#ffffff">Intérprete:&#8221;       # Tela montada com um único echo<br />
while true<br />
do<br />
tput cup 5 38; tput el              # Posiciona e limpa linha<br />
read Album<br />
[ ! "$Album" ] &amp;&amp;                   # Operador deu<br />
{<br />
source pergunta.func &#8220;Deseja Terminar&#8221; s n<br />
[ $SN = "n" ] &amp;&amp; continue       # Agora só testo a caixa baixa<br />
clear; exit                     # Fim da execução<br />
}<br />
grep -iq &#8220;^$Album^&#8221; musicas 2&gt; /dev/null &amp;&amp;<br />
{<br />
. mandamsg.func Este álbum já está cadastrado<br />
continue                        # Volta para ler outro álbum<br />
}<br />
Reg=&#8221;$Album^&#8221;                       # $Reg receberá os dados de gravação<br />
oArtista=                           # Guardará artista anterior<br />
while true<br />
do<br />
((Faixa++))<br />
tput cup 7 38<br />
echo $Faixa<br />
tput cup 9 38                   # Posiciona para ler musica<br />
read Musica<br />
[ "$Musica" ] ||                # Se o operador tiver dado &#8230;<br />
{<br />
. pergunta.func &#8220;Fim de Álbum?&#8221; s n<br />
[ "$SN" = n ] &amp;&amp; continue   # Agora só testo a caixa baixa<br />
break                       # Sai do loop para gravar dados<br />
}<br />
tput cup 11 38                           # Posiciona para ler Artista<br />
[ "$oArtista" ] &amp;&amp; echo -n &#8220;($oArtista) &#8221;  # Artista anter. é default<br />
read Artista<br />
[ "$Artista" ] &amp;&amp; oArtista=&#8221;$Artista&#8221;<br />
Reg=&#8221;$Reg$oArtista~$Musica:&#8221;               # Montando registro<br />
tput cup 9 38; tput el                     # Apaga Musica da tela<br />
tput cup 11 38; tput el                    # Apaga Artista da tela<br />
done<br />
echo &#8220;$Reg&#8221; &gt;&gt; musicas                 # Grava registro no fim do arquivo<br />
sort musicas -o musicas                # Classifica o arquivo<br />
done</font></div>
<p>Agora o programa deu uma boa encolhida e as chamadas de função foram trocadas por arquivos externos chamados <code>pergunta.func</code> e <code>mandamsg.func</code>, que assim podem ser chamados por qualquer outro programa, desta forma reutilizando o seu código.</p>
<p>Por motivos meramente didáticos as execuções de <code>pergunta.func</code> e <code>mandamsg.func</code> estão sendo comandadas por <code>source</code> e por <code>.</code> (ponto) indiscriminadamente, embora prefira o <code>source</code> por ser mais visível desta forma dando maior legibilidade ao código e facilitando sua posterior manutenção.</p>
<p>Veja agora como ficaram estes dois arquivos:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat pergunta.func<font color="#ffffff"><br />
#  A função recebe 3 parâmetros na seguinte ordem:<br />
#  $1 &#8211; Mensagem a ser dada na tela<br />
#  $2 &#8211; Valor a ser aceito com resposta default<br />
#  $3 &#8211; O outro valor aceito<br />
#  Supondo que $1=Aceita?, $2=s e $3=n, a linha<br />
#  abaixo colocaria em Msg o valor &#8220;Aceita? (S/n)&#8221;<br />
Msg=&#8221;$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)&#8221;<br />
TamMsg=${#Msg}<br />
Col=$(((TotCols &#8211; TamMsg) / 2))    # Centra msg na linha<br />
tput cup $LinhaMesg $Col<br />
echo &#8220;$Msg&#8221;<br />
tput cup $LinhaMesg $((Col + TamMsg + 1))<br />
read -n1 SN<br />
[ ! $SN ] &amp;&amp; SN=$2                 # Se vazia coloca default em SN<br />
echo $SN | tr A-Z a-z              # A saída de SN será em minúscula<br />
tput cup $LinhaMesg $Col; tput el  # Apaga msg da tela</font><br />
$ cat mandamsg.func<font color="#ffffff"><br />
# A função recebe somente um parâmetro<br />
# com a mensagem que se deseja exibir,<br />
# para não obrigar ao programador passar<br />
# a msq entre aspas, usaremos $* (todos<br />
# os parâmetro, lembra?) e não $1.<br />
Msg=&#8221;$*&#8221;<br />
TamMsg=${#Msg}<br />
Col=$(((TotCols &#8211; TamMsg) / 2))    # Centra msg na linha<br />
tput cup $LinhaMesg $Col<br />
echo &#8220;$Msg&#8221;<br />
read -n1<br />
tput cup $LinhaMesg $Col; tput el  # Apaga msg da tela</font></div>
<p>Em ambos os arquivos, fiz somente duas mudanças que veremos nas observações a seguir, porém tenho mais três a fazer:</p>
<ol>
<li> As variáveis não estão sendo mais declaradas como <code>local</code>, porque está é uma diretiva que só pode ser usada no corpo de funções e portanto estas variáveis permanecem no ambiente do Shell, poluindo-o;</li>
<li> O comando <code>return</code> não está mais presente mas poderia estar sem alterar em nada a lógica, uma vez que ele só serviria para indicar um eventual erro via um código de retorno previamente estabelecido (por exemplo <code>return 1</code>, <code>return 2</code>, &#8230;), sendo que o <code>return</code> e <code>return 0</code> são idênticos e significam rotina executada sem erros;</li>
<li> O comando que estamos acostumados a usar para gerar código de retorno é o <code>exit</code>, mas a saída de uma rotina externa não pode ser feita desta forma, porque por estar sendo executada no mesmo <i>Shell</i> que o <i>script</i> chamador, o <code>exit</code> simplesmente encerraria este <i>Shell</i>, terminando a execução de todo o <i>script</i>;</li>
<li> De onde surgiu a variável <i>LinhaMesg</i>? Ela veio do <i>musinc7</i>, porque ela havia sido declarada antes da chamada das rotinas (nunca esquecendo que o <i>Shell</i> que está interpretando o <i>script</i> e estas rotinas é o mesmo);</li>
<li> Se você decidir usar rotinas externas, não se avexe, abunde os comentários (principalmente sobre a passagem dos parâmetros) para facilitar a manutenção e seu uso por outros programas no futuro.</li>
</ol>
<p>- Bem, agora você já tem mais um monte de novidade para melhorar os <i>scripts</i> que fizemos você se lembra do programa <code>listartista</code> no qual você passava o nome de um artista como parâmetro e ele devolvia as suas músicas? Ele era assim:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat listartista<font color="#ffffff"><br />
#!/bin/bash<br />
# Dado um artista, mostra as suas musicas<br />
# versao 2<br />
</font><br />
<font color="#ffffff">if  [ $# -eq 0 ]<br />
then<br />
echo Voce deveria ter passado pelo menos um parametro<br />
exit 1<br />
fi<br />
</font><br />
<font color="#ffffff">IFS=&#8221;<br />
:&#8221;<br />
for ArtMus in $(cut -f2 -d^ musicas)<br />
do<br />
echo &#8220;$ArtMus&#8221; | grep -i &#8220;^$*~&#8221; &gt; /dev/null &amp;&amp; echo $ArtMus | cut -f2 -d~<br />
done</font></div>
<p>- Claro que me lembro!&#8230;</p>
<p>- Então para firmar os conceitos que te passei, faça ele com a tela formatada, em <i>loop</i>, de forma que ele só termine quando receber um <code>&lt;ENTER&gt;</code> puro no nome do artista. Ahhh! Quando a listagem atingir a antepenúltima 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 músicas listadas (quantidade de linhas menos 3) o programa aguardará que o operador tecle algo para então prosseguir. Eventuais mensagens de erro devem ser passadas usando a rotina <code>mandamsg.func</code> que acabamos de desenvolver.</p>
<p>- Chico, manda mais dois, o meu é com pouca pressão&#8230;</p>
<p>Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em <i>Shell</i> que mande um e-mail para a nossa <a href="mailto:treinamentos@festivalsoftwarelivre.org?Subject=Curso%20de%20Shell%20com%20Julio%20Neves">gerencia de treinamento</a> para informar-se.</p>
<p>Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para <a href="mailto:julioneves@openoffice.org?Subject=D%C3%BAvidas%20Papo%20de%20Botequim">mim</a>.</p>
<p>Valeu!</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/jneves.wordpress.com/10/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/jneves.wordpress.com/10/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jneves.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jneves.wordpress.com/10/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jneves.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jneves.wordpress.com/10/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jneves.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jneves.wordpress.com/10/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jneves.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jneves.wordpress.com/10/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jneves.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jneves.wordpress.com/10/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jneves.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jneves.wordpress.com/10/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jneves.wordpress.com/10/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jneves.wordpress.com/10/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=10&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-8/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/53f0649d2d6a9b19b90abd0575ee5c7c?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">jneves</media:title>
		</media:content>
	</item>
		<item>
		<title>Papo de Botequim &#8211; Parte 9</title>
		<link>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-9/</link>
		<comments>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-9/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 15:07:54 +0000</pubDate>
		<dc:creator>jneves</dc:creator>
				<category><![CDATA[Shell]]></category>

		<guid isPermaLink="false">http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-9/</guid>
		<description><![CDATA[Envenenando a escrita Principais Variáveis do Shell Expansão de parâmetros &#8211; Tá bom, já sei que você vai querer chope antes de começar, mas tô tão afim de te mostrar o que fiz que já vou até pedindo a rodada e em seguida vou te mostrar. &#8211; Aê Chico, manda dois. O dele é sem [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=9&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div class="twikiToc">
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo009#Envenenando_a_escrita"> Envenenando a escrita</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo009#Principais_Vari%C3%A1veis_do_Shell"> Principais Variáveis do Shell</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo009#Expans%C3%A3o_de_par%C3%A2metros"> Expansão de parâmetros</a></li>
</ul>
</div>
<hr />      &#8211; Tá bom, já sei que você vai querer chope antes de começar, mas tô tão afim de te mostrar o que fiz que já vou até pedindo a rodada e em seguida vou te mostrar.      &#8211; Aê Chico, manda dois. O dele é sem colarinho pra não deixar cheiro ruim neste bigodão&#8230;- Enquanto o chope não chega deixa eu te relembrar que você me pediu para refazer o <code>listartista</code> com a tela formatada, em <i>loop</i>, de forma que ele só termine quando receber um <code>&lt;ENTER&gt;</code> puro no nome do artista. Eventuais mensagens de erros e perguntas deveriam ser dadas na antepenúltima linha da tela utilizando as rotina <code>mandamsg.func</code> e <code>pergunta.func</code> que acabamos de desenvolver.- Primeiramente eu dei uma encolhida no <code>mandamsg.func</code> e no <code>pergunta.func</code>, que ficaram assim:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat mandamsg.func<font color="#ffffff"><br />
# A  função recebe  somente um parâmetro<br />
# com a  mensagem que  se deseja exibir,<br />
# para não obrigar ao programador passar<br />
# a msg  entre aspas, usaremos $* (todos<br />
# os parâmetro, lembra?) e não $1.<br />
Msg=&#8221;$*&#8221;<br />
TamMsg=${#Msg}<br />
Col=$(((TotCols &#8211; TamMsg) / 2))    # Centra msg na linha<br />
tput cup $LinhaMesg $Col<br />
read -n1 -p &#8220;$Msg &#8220;</font></div>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat pergunta.func<font color="#ffffff"><br />
#  A função recebe 3 parâmetros na seguinte ordem:<br />
#  $1 &#8211; Mensagem a ser dada na tela<br />
#  $2 &#8211; Valor a ser aceito com resposta default<br />
#  $3 &#8211; O outro valor aceito<br />
#  Supondo que $1=Aceita?, $2=s e $3=n, a linha<br />
#  abaixo colocaria em Msg o valor &#8220;Aceita? (S/n)&#8221;<br />
Msg=&#8221;$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)&#8221;<br />
TamMsg=${#Msg}<br />
Col=$(((TotCols &#8211; TamMsg) / 2))    # Centra msg na linha<br />
tput cup $LinhaMesg $Col<br />
read -n1 -p &#8220;$Msg &#8221; SN<br />
[ ! $SN ] &amp;&amp; SN=$2                 # Se vazia coloca default em SN<br />
SN=$(echo $SN | tr A-Z a-z)        # A saída de SN será em minúscula<br />
tput cup $LinhaMesg $Col; tput el  # Apaga msg da tela</font></div>
<p>- E agora aí vai o grandão:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat listartista3<font color="#ffffff"><br />
#!/bin/bash<br />
# Dado um artista, mostra as suas musicas<br />
# versao 3<br />
</font><br />
<font color="#ffffff">LinhaMesg=$((`tput lines` &#8211; 3))  # Linha que msgs serão dadas para operador<br />
TotCols=$(tput cols)             # Qtd colunas da tela para enquadrar msgs<br />
</font><br />
<font color="#ffffff">clear<br />
echo &#8220;<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+<br />
|  Lista Todas as Músicas de um Determinado Artista  |<br />
|  &#8212;&#8211; &#8212;&#8211; &#8212; &#8212;&#8212;- &#8212; &#8211; &#8212;&#8212;&#8212;&#8211; &#8212;&#8212;-  |<br />
|                                                    |<br />
|  Informe o Artista:                                |<br />
+&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;&#8212;-+&#8221;<br />
while true<br />
do<br />
tput cup 5 51; tput ech 31  # ech=Erase chars (31 caracteres para não apagar barra vertical)<br />
read Nome<br />
if  [ ! "$Nome" ]           # $Nome estah vazio?<br />
then<br />
. pergunta.func &#8220;Deseja Sair?&#8221; s n<br />
[ $SN = n ] &amp;&amp; continue<br />
break<br />
fi<br />
</font><br />
<font color="#ffffff">    fgrep -iq &#8220;^$Nome~&#8221; musicas || # fgrep não interpreta ^ como expressão regular<br />
{<br />
. mandamsg.func &#8220;Não existe música deste artista&#8221;<br />
continue<br />
}<br />
</font><br />
<font color="#ffffff">    tput cup 7 29; echo &#8216;|                                                    |&#8217;<br />
LinAtual=8<br />
IFS=&#8221;<br />
:&#8221;<br />
for ArtMus in $(cut -f2 -d^ musicas) # Exclui nome do album<br />
do<br />
if  echo &#8220;$ArtMus&#8221; | grep -iq &#8220;^$Nome~&#8221;<br />
then<br />
tput cup $LinAtual 29<br />
echo -n &#8216;|  &#8216;<br />
echo $ArtMus | cut -f2 -d~<br />
tput cup $LinAtual 82<br />
echo &#8216;|&#8217;<br />
let LinAtual++<br />
if  [ $LinAtual -eq $LinhaMesg ]<br />
then<br />
. mandamsg.func &#8220;Tecle Algo para Continuar&#8230;&#8221;<br />
tput cup 7 0; tput ed  # Apaga a tela a partir da linha 7<br />
tput cup 7 29; echo &#8216;|                                                    |&#8217;<br />
LinAtual=8<br />
fi<br />
fi<br />
done<br />
tput cup $LinAtual 29; echo &#8216;|                                                    |&#8217;<br />
tput cup $((++LinAtual)) 29<br />
read -n1 -p &#8220;+&#8212;&#8212;&#8212;&#8211;Tecle Algo para Nova Consulta&#8212;&#8212;&#8212;&#8212;+&#8221;<br />
tput cup 7 0; tput ed              # Apaga a tela a partir da linha 7<br />
done</font></div>
<p>- Poxa, você chegou com a corda toda! Mas gostei da forma que você resolveu o problema e estruturou o programa. Foi mais trabalhoso mas a apresentação ficou legal e você explorou bastante as opções do <code>tput</code>. Vamos testar o resultado com um álbum do <i>Emerson, Lake &amp; Palmer</i> que tenho cadastrado:</p>
<pre>              +----------------------------------------------------+
              |  Lista Todas as Músicas de um Determinado Artista  |
              |  ----- ----- -- ------- -- -- ----------- -------  |
              |                                                    |
              |  Informe o Artista: Emerson, Lake &amp; Palmer         |
              +----------------------------------------------------+
              |                                                    |
              |  Jerusalem                                         |
              |  Toccata                                           |
              |  Still ... You Turn Me On                          |
              |  Benny The Bouncer                                 |
              |  Karn Evil 9                                       |
              |                                                    |
              +-----------Tecle Algo para Nova Consulta------------+</pre>
<h2><a title="Envenenando_a_escrita" name="Envenenando_a_escrita"></a> Envenenando a escrita</h2>
<p>- Ufa! Agora você já sabe tudo sobre leitura, mas sobre escrita está apenas engatinhando. Já sei que você vai me perguntar:<br />
- Ora, não é com o comando <code>echo</code> e com os redirecionamentos de saída que se escreve?</p>
<p>É, com estes comandos você escreve 90% das coisas necessárias, porém se precisar de escrever algo formatado eles lhe darão muito trabalho. Para formatar a saída veremos agora uma instrução muito interessante &#8211; é o <code>printf</code> &#8211; sua sintaxe é a seguinte:</p>
<pre>    printf formato [argumento...]</pre>
<p>Onde:<br />
<code>formato</code> &#8211;   é uma cadeia de caracteres que contem 3 tipos de objeto:</p>
<ol>
<li> caracteres simples;</li>
<li> caracteres para especificação de formato;</li>
<li> seqüência de escape no padrão da linguagem C.</li>
</ol>
<p><code>Argumento</code> &#8211;   é a cadeia a ser impressa sob o controle do <code>formato</code>. Cada um dos caracteres utilizados para especificação de <code>formato</code> é precedido pelo caracter <code>%</code> e logo a seguir vem a especificação de <code>formato</code> de acordo com a tabela:</p>
<table class="twikiTable" border="0" cellpadding="4" cellspacing="1">
<tr>
<th colspan="2" class="twikiFirstCol" align="center" bgcolor="#0000ff"><b><font color="#ffff00">Tabela dos Caracteres de Formatação do printf</font></b></th>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><b>Letra</b></td>
<td bgcolor="#dddddd"><b>A expressão será impressa como:</b></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>c</code></td>
<td bgcolor="#bbbbbb">Simples caractere</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><code>d</code></td>
<td bgcolor="#dddddd">Número no sistema decimal</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>e</code></td>
<td bgcolor="#bbbbbb">Notação científica exponencial</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><code>f</code></td>
<td bgcolor="#dddddd">Número com ponto decimal (<i>float</i>)</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>g</code></td>
<td bgcolor="#bbbbbb">O menor entre os formatos <code>%e</code> e <code>%f</code> com supressão dos zeros não significativos</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><code>o</code></td>
<td bgcolor="#dddddd">Número no sistema octal</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>s</code></td>
<td bgcolor="#bbbbbb">Cadeia de caracteres</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><code>x</code></td>
<td bgcolor="#dddddd">Número no sistema hexadecimal</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>%</code></td>
<td bgcolor="#bbbbbb">Imprime um <code>%</code>. Não existe nenhuma conversão</td>
</tr>
</table>
<p>As seqüências de <i>escape</i> padrão da linguagem C são sempre precedidas por um contra-barra (<code></code>) e as reconhecidas pelo comando <code>printf</code> são:</p>
<table class="twikiTable" border="0" cellpadding="4" cellspacing="1">
<tr>
<th colspan="2" class="twikiFirstCol" align="center" bgcolor="#0000ff"><b><font color="#ffff00">Sequencias de <i>Escape</i> do printf</font></b></th>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><b>Seqüência</b></td>
<td bgcolor="#dddddd"><b>Efeito</b></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>a</code></td>
<td bgcolor="#bbbbbb">Soa o beep</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><code>b</code></td>
<td bgcolor="#dddddd">Volta uma posição (<i>backspace</i>)</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>f</code></td>
<td bgcolor="#bbbbbb">Salta para a próxima página lógica (<i>form feed</i>)</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><code>n</code></td>
<td bgcolor="#dddddd">Salta para o início da linha seguinte (<i>line feed</i>)</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb"><code>r</code></td>
<td bgcolor="#bbbbbb">Volta para o início da linha corrente (<i>carriage return</i>)</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd"><code>t</code></td>
<td bgcolor="#dddddd">Avança para a próxima marca de tabulação</td>
</tr>
</table>
<p>Não acabou por aí não! Tem muito mais coisa sobre a instrução, 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 comentários, que não estou aqui para encher o saco de ninguém.</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ printf &#8220;%c&#8221; &#8220;1 caracter&#8221;<font color="#ffffff"><br />
1</font>$                                  <font color="#ff00ff">Errado! Só listou 1 caractere e não saltou linha ao final</font><br />
$ printf &#8220;%cn&#8221; &#8220;1 caracter&#8221;<font color="#ffffff"><br />
1</font>                                   <font color="#ff00ff">Saltou linha mas ainda não listou a cadeia inteira</font><br />
$ printf &#8220;%c caracteren&#8221; 1<font color="#ffffff"><br />
1 caractere</font>                         <font color="#ff00ff">Esta é a forma correta o %c recebeu o 1</font><br />
$ a=2<br />
$ printf &#8220;%c caracteresn&#8221; $a<font color="#ffffff"><br />
2 caracteres</font>                        <font color="#ff00ff">O %c recebeu o valor da variável $a</font><br />
$ printf &#8220;%10c caracteresn&#8221; $a<font color="#ffffff"><br />
2 caracteres</font><br />
$ printf &#8220;%10cn&#8221; $a caracteres<font color="#ffffff"><br />
2<br />
c</font></div>
<p>Repare que nos dois últimos exemplos, em virtude do <code>%c</code>, só foi listado um caracter de cada cadeia. O <code>10</code> à frente do <code>c</code>, não significa 10 caracteres. Um número seguindo o sinal de percentagem (<code>%</code>) significa o tamanho que a cadeia terá após a execução do comando.</p>
<p>E tome de exemplo:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ printf &#8220;%dn&#8221; 32<font color="#ffffff"><br />
32</font><br />
$ printf &#8220;%10dn&#8221; 32<font color="#ffffff"><br />
32</font>                          <font color="#ff00ff">Preenche com brancos à esquerda e não com zeros</font><br />
$ printf &#8220;%04dn&#8221; 32<font color="#ffffff"><br />
0032</font>                                <font color="#ff00ff">04 após % significa 4 dígitos com zeros à esquerda</font><br />
$ printf &#8220;%en&#8221; $(echo &#8220;scale=2 ; 100/6&#8243; | bc)<font color="#ffffff"><br />
1.666000e+01</font>                        <font color="#ff00ff">O default do %e é 6 decimais</font><br />
$ printf &#8220;%.2en&#8221; `echo &#8220;scale=2 ; 100/6&#8243; | bc`<font color="#ffffff"><br />
1.67e+01</font>                            <font color="#ff00ff">O .2 especificou duas decimais</font><br />
$ printf &#8220;%fn&#8221; 32.3<font color="#ffffff"><br />
32.300000</font>                           <font color="#ff00ff">O default do %f é 6 decimais</font><br />
$ printf &#8220;%.2fn&#8221; 32.3<font color="#ffffff"><br />
32.30</font>                               <font color="#ff00ff">O .2 especificou duas decimais</font><br />
$ printf &#8220;%.3fn&#8221; `echo &#8220;scale=2 ; 100/6&#8243; | bc`<font color="#ffffff"><br />
33.330</font>                              <font color="#ff00ff">O bc devolveu 2 decimais. o printf colocou 0 à direita</font><br />
$ printf &#8220;%on&#8221; 10<font color="#ffffff"><br />
12</font>                                  <font color="#ff00ff">Converteu o 10 para octal</font><br />
$ printf &#8220;%03on&#8221; 27<font color="#ffffff"><br />
033</font>                                 <font color="#ff00ff">Assim a conversão fica com mais jeito de octal, né?</font><br />
$ printf &#8220;%sn&#8221; Peteleca<font color="#ffffff"><br />
Peteleca</font><br />
$ printf &#8220;%15sn&#8221; Peteleca<font color="#ffffff"><br />
Peteleca</font>                     <font color="#ff00ff">Peteleca com 15 caracteres enchidos com brancos</font><br />
$ printf &#8220;%-15sNevesn&#8221; Peteleca<font color="#ffffff"><br />
Peteleca       Neves</font>                <font color="#ff00ff">O menos (-) encheu à direita com brancos</font><br />
$ printf &#8220;%.3sn&#8221; Peteleca<font color="#ffffff"><br />
Pet</font>                                 <font color="#ff00ff">3 trunca as 3 primeiras</font><br />
$ printf &#8220;%10.3san&#8221; Peteleca<font color="#ffffff"><br />
Peta</font>                         <font color="#ff00ff">Pet com 10 caracteres concatenado com a (após o s)</font><br />
$ printf &#8220;EXEMPLO %xn&#8221; 45232<font color="#ffffff"><br />
EXEMPLO b0b0</font>                        <font color="#ff00ff">Transformou para hexa mas os zeros não combinam</font><br />
$ printf &#8220;EXEMPLO %Xn&#8221; 45232<font color="#ffffff"><br />
EXEMPLO B0B0</font>                        <font color="#ff00ff">Assim disfarçou melhor (repare o X maiúsculo)</font><br />
$ printf &#8220;%X %XL%Xn&#8221; 49354 192 10<font color="#ffffff"><br />
C0CA C0LA</font></div>
<p>O último exemplo não é <i>marketing</i> e é bastante completo, vou comentá-lo passo-a-passo:</p>
<ol>
<li> O primeiro <code>%X</code> converteu <code>49354</code> em hexadecimal resultando <code>C0CA</code> (leia-se &#8220;cê&#8221;, &#8220;zero&#8221;, &#8220;cê&#8221; e &#8220;a&#8221;);</li>
<li> Em seguida veio um espaço em branco seguido por outro <code>%XL</code>. O <code>%X</code> converteu o <code>192</code> dando como resultado <code>C0</code> que com o <code>L</code> fez <code>C0L</code>;</li>
<li> E finalmente o último <code>%X</code> transformou o <code>10</code> em <code>A</code>.</li>
</ol>
<p>Conforme vocês podem notar, a instrução <code>printf</code> é bastante completa e complexa (ainda bem que o <code>echo</code> resolve quase tudo).</p>
<p>Creio que quando resolvi explicar o <code>printf</code> através de exemplos, acertei em cheio pois não saberia como enumerar tantas regrinhas sem tornar a leitura enfadonha.</p>
<h2><a title="Principais_Variáveis_do_Shell" name="Principais_Variáveis_do_Shell"></a> Principais Variáveis do <i>Shell</i></h2>
<p>O <i>Bash</i> possui diversas variáveis que servem para dar informações sobre o ambiente ou alterá-lo. Seu número é muito grande e não pretendo mostrar todas, mas uma pequena parte que pode lhe ajudar na elaboração de <i>scripts</i>. Então aí vão as principais:</p>
<table class="twikiTable" border="0" cellpadding="4" cellspacing="1">
<tr>
<th colspan="2" class="twikiFirstCol" align="center" bgcolor="#0000ff"><b><font color="#ffff00">Principais variáveis do Bash</font></b></th>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><b>Variável</b></td>
<td bgcolor="#dddddd"><b>Conteúdo</b></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb">CDPATH</td>
<td bgcolor="#bbbbbb">Contém os caminhos que serão pesquisados para tentar localizar um diretório especificado. Apesar desta variável ser pouco conhecida, seu uso deve ser incentivado por poupar muito trabalho, principalmente em instalações com estrutura de diretórios com bastante níveis.</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd">HISTSIZE</td>
<td bgcolor="#dddddd">Limita o número de instruções que cabem dentro do arquivo de histórico de comandos (normalmente <code>.bash_history</code> mas efetivamente é o que está armazenado na variável <code>$HISTFILE</code>). Seu valor <i>default</i> é 500.</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb">HOSTNAME</td>
<td bgcolor="#bbbbbb">O nome do host corrente (que também pode ser obtido com o comando <code>uname -n</code>).</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd">LANG</td>
<td bgcolor="#dddddd">Usada para determinar a língua falada no pais (mais especificamente categoria do locale).</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb">LINENO</td>
<td bgcolor="#bbbbbb">O número da linha do <i>script</i> ou da função que está sendo executada, seu uso principal é para dar mensagens de erro juntamente com as variáveis <code>$0</code> (nome do programa) e <code>$FUNCNAME</code> (nome da função em execução)</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd">LOGNAME</td>
<td bgcolor="#dddddd">Armazena o nome de <i>login</i> do usuário.</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb">MAILCHECK</td>
<td bgcolor="#bbbbbb">Especifica, em segundos, a freqüência que o Shell verificará a presença de correspondências nos arquivos indicados pela variáveis <code>$MAILPATH</code> ou <code>$MAIL</code>. O tempo padrão é 60 segundos. Uma vez este tempo expirado, o <i>Shell</i> fará esta verificação antes de exibir o próximo <i>prompt</i> primário (definido em <code>$PS1</code>). Se esta variável estiver sem valor ou com um valor menor ou igual a zero, a verificação de novas correspondências não será efetuada.</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd">PATH</td>
<td bgcolor="#dddddd">Caminhos que serão pesquisados para tentar localizar um arquivo especificado. Como cada <i>script</i> é um arquivo, caso use o diretório corrente (<code>.</code>) na sua variável <code>$PATH</code>, você não necessitará de usar o <code>./scrp</code> para que <code>scrp</code> seja executado. Basta fazer <code>scrp</code>. Este é o modo que procedo aqui no Botequim.</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb">PIPESTATUS</td>
<td bgcolor="#bbbbbb">É uma variável do tipo vetor (<i>array</i>) que contém uma lista valores de código de retorno do último <i>pipeline</i> executado, isto é, um <i>array</i> que abriga cada um dos <code>$?</code> de cada instrução do último <i>pipeline</i>.</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd">PROMPT_COMMAND</td>
<td bgcolor="#dddddd">Se esta variável receber uma instrução, toda vez que você der um <code>&lt;ENTER&gt;</code> direto no prompt principal (<code>$PS1</code>), este comando será executado. É útil quando se está repetindo muito uma determinada instrução.</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb">PS1</td>
<td bgcolor="#bbbbbb">É o <i>prompt</i> principal. No &#8220;Papo de Botequim&#8221; usamos os seus <i>defaults</i>: <code>$</code> para usuário comum e <code>#</code> para <i>root</i>, mas é muito freqüente que ele esteja customizado. Uma curiosidade é que existe até concurso de quem programa o <code>$PS1</code> mais criativo. <a href="http://www.google.com.br/search?num=100&amp;hl=pt-BR&amp;q=+%22PS1%22++Linux++prompt+personalizar+alterar&amp;btnG=Pesquisar&amp;meta=cr=countryBR" target="_blank">(clique para dar uma googlada)</a></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd">PS2</td>
<td bgcolor="#dddddd">Também chamado <i>prompt</i> de continuação, é aquele sinal de maior (<code>&gt;</code>) que aparece após um <code>&lt;ENTER&gt;</code> sem o comando ter sido encerrado.</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb">PWD</td>
<td bgcolor="#bbbbbb">Possui o caminho completo (<code>$PATH</code>) do diretório corrente. Tem o mesmo efeito do comando <code>pwd</code>.</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd">RANDOM</td>
<td bgcolor="#dddddd">Cada vez que esta variável é acessada, devolve um número inteiro, que é um randômico entre 0 e 32767.</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb">REPLY</td>
<td bgcolor="#bbbbbb">Use esta variável para recuperar o último campo lido, caso ele não tenha nenhuma variável associada.</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#dddddd">SECONDS</td>
<td bgcolor="#dddddd">Esta variável contém a quantidade de segundos que o <i>Shell</i> corrente está de pé. Use-a somente para esnobar um usuários daquilo que chamam de sistema operacional, mas necessita de <i>boots</i> freqüentes.  <img src="http://twiki.softwarelivre.org/pub/TWiki/SmiliesPlugin/smile.gif" alt="smile" border="0" /></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#bbbbbb">TMOUT</td>
<td bgcolor="#bbbbbb">Se tiver um valor maior do que zero, este valor será tomado como o padrão de <i>timeout</i> do comando <code>read</code>. No <i>prompt</i>, este valor é interpretado como o tempo de espera por uma ação antes de expirar a sessão. Supondo que a variável contenha 30, o <i>Shell</i> dará <i>logout</i> após 30 segundos de <i>prompt</i> sem nenhuma ação.</td>
</tr>
</table>
<ul>
<li> <b>CDPATH</b></li>
</ul>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo $CDPATH<font color="#ffffff"><br />
.:..:~:/usr/local</font><br />
$ pwd<font color="#ffffff"><br />
/home/jneves/LM</font><br />
$ cd bin<br />
$ pwd<font color="#ffffff"><br />
/usr/local/bin</font></div>
<p>Como /usr/local estava na minha variável <code>$CDPATH</code>, e não existia o diretório <code>bin</code> em nenhum dos seus antecessores (<code>.</code>, <code>..</code> e <code>~</code>), o <code>cd</code> foi executado para <code>/usr/local/bin</code></p>
<ul>
<li> <b>LANG</b></li>
</ul>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ date<font color="#ffffff"><br />
Thu Apr 14 11:54:13 BRT 2005</font><br />
$ LANG=pt_BR date<font color="#ffffff"><br />
Qui Abr 14 11:55:14 BRT 2005</font></div>
<p>Com a especificação da variável <code>LANG=pt_BR</code> (português do Brasil), a data passou a ser informada no padrão brasileiro. É interessante observarmos que não foi usado ponto-e-vírgula (<code>;</code>) para separar a atribuição de <code>LANG</code> do comando <code>date</code>.</p>
<ul>
<li> <b>PIPESTATUS</b></li>
</ul>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ who<font color="#ffffff"><br />
jneves   pts/0        Apr 11 16:26 (10.2.4.144)<br />
jneves   pts/1        Apr 12 12:04 (10.2.4.144)</font><br />
$ who | grep ^botelho<br />
$ echo ${PIPESTATUS[*]}<font color="#ffffff"><br />
0 1</font></div>
<p>Neste exemplo mostramos que o usuário <code>botelho</code> não estava &#8220;logado&#8221;, em seguida executamos um <i>pipeline</i> que procurava por ele. Usa-se a notação <code>[*]</code> em um <i>array</i> para listar todos os seus elementos, e desta forma vimos que a primeira instrução (<code>who</code>) foi bem sucedida (código de retorno 0) e a seguinte (<code>grep</code>), não (código de retorno 1).</p>
<ul>
<li> <b>RANDOM</b></li>
</ul>
<p>Para gerar randomicamente um inteiro entre 0 e 100,  fazemos:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo $((RANDOM%101))<font color="#ffffff"><br />
73</font></div>
<p>Ou seja pegamos o resto da divisão por <code>101</code> do número randômico gerado, porque o resto da divisão de qualquer número  por 101 varia entre 0 e 100.</p>
<ul>
<li> <b>REPLY</b></li>
</ul>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ read -p &#8220;Digite S ou N: &#8220;<font color="#ffffff"><br />
Digite S ou N:</font> N<br />
$ echo $REPLY<font color="#ffffff"><br />
N</font></div>
<p>Eu sou do tempo que memória era um bem precioso que custava muuuuito caro. Então para pegar um <code>S</code> ou um <code>N</code>, não costumo a alocar um espaço especial e assim sendo, pego o que foi digitado na variável <code>$REPLY</code>.</p>
<h2><a title="Expansão_de_parâmetros" name="Expansão_de_parâmetros"></a> Expansão de parâmetros</h2>
<p>Bem, muito do que vimos até agora são comandos externos ao <i>Shell</i>. Eles quebram o maior galho, facilitam a visualização, manutenção e depuração do código, mas não são tão eficientes quanto os intrínsecos (<i>built-ins</i>). Quando o nosso problema for performance, devemos dar preferência ao uso dos intrínsecos e a partir de agora vou te mostrar algumas técnicas para o teu programa pisar no acelerador.</p>
<p>Na tabela e exemplos a seguir, veremos uma série de construções chamadas expansão (ou substituição) de parâmetros (<i>Parameter Expansion</i>), que substituem instruções como o <code>cut</code>, o <code>expr</code>, o <code>tr</code>, o <code>sed</code> e outras de forma mais ágil.</p>
<table class="twikiTable" border="0" cellpadding="4" cellspacing="1">
<tr>
<th colspan="2" class="twikiFirstCol" align="center" bgcolor="#0000ff"><b><font color="#ffff00">Expansão de parâmetros</font></b></th>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><b>Expressão</b></td>
<td bgcolor="#dddddd"><b>Resultado esperado</b></td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#bbbbbb"><code>${var:-padrao}</code></td>
<td bgcolor="#bbbbbb">Se <code>var</code> não tem valor, o resultado da expressão é <code>padrao</code></td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><code>${#cadeia}</code></td>
<td bgcolor="#dddddd">Tamanho de <code>$cadeia</code></td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#bbbbbb"><code>${cadeia:posicao}</code></td>
<td bgcolor="#bbbbbb">Extrai uma subcadeia de <code>$cadeia</code> a partir de <code>posicao</code>. Origem zero</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><code>${cadeia:posicao:tamanho}</code></td>
<td bgcolor="#dddddd">Extrai uma subcadeia de <code>$cadeia</code> a partir de <code>posicao</code> com tamanho igual a <code>tamanho</code>. Origem zero</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#bbbbbb"><code>${cadeia#expr}</code></td>
<td bgcolor="#bbbbbb">Corta a menor ocorrência de <code>$cadeia</code> à esquerda da expressão <code>expr</code></td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><code>${cadeia##expr}</code></td>
<td bgcolor="#dddddd">Corta a maior ocorrência de <code>$cadeia</code> à esquerda da expressão <code>expr</code></td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#bbbbbb"><code>${cadeia%expr}</code></td>
<td bgcolor="#bbbbbb">Corta a menor ocorrência de <code>$cadeia</code> à direita da expressão <code>expr</code></td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><code>${cadeia%%expr}</code></td>
<td bgcolor="#dddddd">Corta a maior ocorrência de <code>$cadeia</code> à direita da expressão <code>expr</code></td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#bbbbbb"><code>${cadeia/subcad1/subcad2}</code></td>
<td bgcolor="#bbbbbb">Troca em <code>$cadeia</code> a primeira ocorrência de <code>subcad1</code> por <code>subcad2</code></td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><code>${cadeia//subcad1/subcad2}</code></td>
<td bgcolor="#dddddd">Troca em <code>$cadeia</code> todas as ocorrências de <code>subcad1</code> por <code>subcad2</code></td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#bbbbbb"><code>${cadeia/#subcad1/subcad2}</code></td>
<td bgcolor="#bbbbbb">Se <code>subcad1</code> combina com o início de <code>$cadeia</code>, então é trocado por <code>subcad2</code></td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#dddddd"><code>${cadeia/%subcad1/subcad2}</code></td>
<td bgcolor="#dddddd">Se <code>subcad1</code> combina com o fim de <code>$cadeia</code>, então é trocado por <code>subcad2</code></td>
</tr>
</table>
<ul>
<li> Se em uma pergunta o <code>S</code> é oferecido como valor <i>default</i> (padrão) e a saída vai para a variável <code>$SN</code>, após ler o valor podemos fazer:</li>
</ul>
<pre>    SN=$(SN:-S}</pre>
<p>Desta forma se o operador deu um simples <code>&lt;ENTER&gt;</code> para confirmar que aceitou o valor <i>default</i>, após executar esta instrução, a variável terá o valor <code>S</code>, caso contrário, terá o valor digitado.</p>
<ul>
<li> Para sabermos o tamanho de uma cadeia:</li>
</ul>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cadeia=0123<br />
$ echo ${#cadeia}<font color="#ffffff"><br />
4</font></div>
<ul>
<li> Para extrair de uma cadeia da posição um até o final fazemos:</li>
</ul>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cadeia=abcdef<br />
$ echo ${cadeia:1}<font color="#ffffff"><br />
bcdef</font></div>
<p>Repare que a origem é zero e não um.</p>
<ul>
<li> Na mesma variável <code>$cadeia</code> do exemplo acima, para extrair 3 caracteres a partir da 2ª posição:</li>
</ul>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo ${cadeia:2:3}<font color="#ffffff"><br />
cde</font></div>
<p>Repare que novamente que a origem da contagem é zero e não um.</p>
<ul>
<li> Para suprimir tudo à esquerda da primeira ocorrência de uma cadeia, faça:</li>
</ul>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cadeia=&#8221;Papo de Botequim&#8221;<br />
$ echo ${cadeia#*&#8217; &#8216;}<font color="#ffffff"><br />
de Botequim</font><br />
$ echo &#8220;Conversa &#8220;${cadeia#*&#8217; &#8216;}<font color="#ffffff"><br />
Conversa de Botequim</font></div>
<p>Neste exemplo foi suprimido à esquerda tudo que casasse com a menor ocorrência da expressão <code>*' '</code>, ou seja, tudo até o primeiro espaço em branco.</p>
<p>Estes exemplos também poderiam ser escritos sem protegermos o espaço da interpretação do Shell (mas prefiro protegê-lo para facilitar a legibilidade do código), veja:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo ${cadeia#* }<font color="#ffffff"><br />
de Botequim</font><br />
$ echo &#8220;Conversa &#8220;${cadeia#* }<font color="#ffffff"><br />
Conversa de Botequim</font></div>
<p>Repare que na construção de <code>expr</code> é permitido o uso de metacaracteres.</p>
<ul>
<li> Utilizando o mesmo valor da variável <code>$cadeia</code>, observe como faríamos para termos somente <code>Botequim</code>:</li>
</ul>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo ${cadeia##*&#8217; &#8216;}<font color="#ffffff"><br />
Botequim</font><br />
$ echo &#8220;Vamos &#8216;Chopear&#8217; no &#8220;${cadeia##*&#8217; &#8216;}<font color="#ffffff"><br />
Vamos &#8216;Chopear&#8217; no Botequim</font></div>
<p>Desta vez suprimimos à esquerda de cadeia a maior ocorrência da expressão <code>expr</code>. Assim como no caso anterior, o uso de metacaracteres é permitido.</p>
<p>Outro exemplo mais útil: para que não apareça o caminho (<i>path</i>) completo do seu programa (que, como já sabemos está contido na variável <code>$0</code>) em uma mensagem de erro, inicie o seu texto da seguinte forma:</p>
<pre>    echo Uso: ${0##*/} texto da mensagem de erro</pre>
<p>Neste exemplo seria suprimido à esquerda tudo até a última barra (<code>/</code>) do caminho (<i>path</i>), desta forma sobrando somente o nome do programa.</p>
<ul>
<li> O uso do percentual (<code>%</code>) é como se olhássemos o jogo-da-velha (<code>#</code>) no espelho, isto é, são simétricos. Então vejamos um exemplo para provar isso:</li>
</ul>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo $cadeia<font color="#ffffff"><br />
Papo de Botequim</font><br />
$ echo ${cadeia%&#8217; &#8216;*}<font color="#ffffff"><br />
Papo de</font><br />
$ echo ${cadeia%%&#8217; &#8216;*}<font color="#ffffff"><br />
Papo</font></div>
<ul>
<li> Para trocar primeira ocorrência de uma subcadeia em uma cadeia por outra:</li>
</ul>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo $cadeia<font color="#ffffff"><br />
Papo de Botequim</font><br />
$ echo ${cadeia/de/no}<font color="#ffffff"><br />
Papo no Botequim</font><br />
$ echo ${cadeia/de /}<font color="#ffffff"><br />
Papo Botequim</font></div>
<p>Neste caso preste a atenção quando for usar metacaracteres, eles são gulosos! Eles sempre combinarão com a maior possibilidade, veja o exemplo a seguir onde a intenção era trocar <code>Papo de Botequim</code> por <code>Conversa de Botequim</code>:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo $cadeia<font color="#ffffff"><br />
Papo de Botequim</font><br />
$ echo ${cadeia/*o/Conversa}<font color="#ffffff"><br />
Conversatequim</font></div>
<p>A idéia era pegar tudo até o primeiro <code>o</code>, mas o que foi trocado foi tudo até o último <code>o</code>. Isto poderia ser resolvido de diversas maneiras, veja algumas:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo ${cadeia/*po/Conversa}<font color="#ffffff"><br />
Conversa de Botequim</font><br />
$ echo ${cadeia/????/Conversa}<font color="#ffffff"><br />
Conversa de Botequim</font></div>
<ul>
<li> Trocando todas as ocorrências de uma subcadeia por outra. Quando fazemos:</li>
</ul>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo ${cadeia//o/a}<font color="#ffffff"><br />
Papa de Batequim</font></div>
<p>Trocamos todos as letras <code>o</code> por <code>a</code>. Outro exemplo mais útil é para contarmos a quantidade de arquivos existentes no diretório corrente. Observe a linha a seguir:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ ls | wc -l<font color="#ffffff"><br />
30</font></div>
<p>Viu? O <code>wc</code> produz um monte de espaços em branco no início. Para tirá-los podemos fazer:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ QtdArqs=$(ls | wc -l) # QtdArqs recebe a saída do comando<br />
$ echo ${QtdArqs// /}<font color="#ffffff"><br />
30</font></div>
<p>No último exemplo, como eu sabia que a saída era composta de brancos e números, montei esta expressão para trocar todos os espaços por nada. Repare que após as duas primeiras barras existe um espaço em branco.</p>
<p>Outra forma de fazer a mesma coisa seria:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo ${QtdArqs/* /}<font color="#ffffff"><br />
30</font></div>
<ul>
<li> Trocando uma subcadeia no início ou no fim de uma variável. Para trocar no início fazemos:</li>
</ul>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo $Passaro<font color="#ffffff"><br />
quero quero</font><br />
$ echo &#8220;Como diz o sulista &#8211; &#8220;${Passaro/#quero/não}<font color="#ffffff"><br />
Como diz o sulista &#8211; não quero</font></div>
<p>Para trocar no final fazemos:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo &#8220;Como diz o nordestino &#8211; &#8220;${Passaro/%quero/não}<font color="#ffffff"><br />
Como diz o nordestino &#8211; quero não</font></div>
<p>- 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 mengão. Na próxima vou te dar moleza e só vou cobrar o seguinte: pegue a rotina <code>pergunta.func</code>, (a que na qual falamos no início do nosso bate papo de hoje) e otimize-a para que a variável <code>$SN</code> receba o valor <i>default</i> por expansão de parâmetros, como vimos.</p>
<p>- Chico, vê se não esquece de mim e enche meu copo.</p>
<p>Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em <i>Shell</i> que mande um e-mail para a nossa <a href="mailto:treinamentos@festivalsoftwarelivre.org?Subject=Curso%20de%20Shell%20com%20Julio%20Neves">gerencia de treinamento</a> para informar-se.</p>
<p>Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para <a href="mailto:julioneves@openoffice.org?Subject=D%C3%BAvidas%20Papo%20de%20Botequim">mim</a>.</p>
<p>Valeu!</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/jneves.wordpress.com/9/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/jneves.wordpress.com/9/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jneves.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jneves.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jneves.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jneves.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jneves.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jneves.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jneves.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jneves.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jneves.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jneves.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jneves.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jneves.wordpress.com/9/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jneves.wordpress.com/9/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jneves.wordpress.com/9/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=9&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jneves.wordpress.com/2008/03/05/papo-de-botequim-parte-9/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/53f0649d2d6a9b19b90abd0575ee5c7c?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">jneves</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWiki/SmiliesPlugin/smile.gif" medium="image">
			<media:title type="html">smile</media:title>
		</media:content>
	</item>
		<item>
		<title>Papo de Botequim &#8211; Parte 10</title>
		<link>http://jneves.wordpress.com/2008/03/05/8/</link>
		<comments>http://jneves.wordpress.com/2008/03/05/8/#comments</comments>
		<pubDate>Wed, 05 Mar 2008 15:04:43 +0000</pubDate>
		<dc:creator>jneves</dc:creator>
				<category><![CDATA[Shell]]></category>
		<category><![CDATA[bash]]></category>
		<category><![CDATA[eval]]></category>
		<category><![CDATA[exit]]></category>
		<category><![CDATA[ftp]]></category>
		<category><![CDATA[getopts]]></category>
		<category><![CDATA[kill]]></category>
		<category><![CDATA[sigchld]]></category>
		<category><![CDATA[sighup]]></category>
		<category><![CDATA[sigint]]></category>
		<category><![CDATA[signal]]></category>
		<category><![CDATA[sigquit]]></category>
		<category><![CDATA[sigterm]]></category>
		<category><![CDATA[sigwinch]]></category>
		<category><![CDATA[sleep]]></category>
		<category><![CDATA[sockets]]></category>
		<category><![CDATA[trap]]></category>

		<guid isPermaLink="false">http://jneves.wordpress.com/2008/03/05/8/</guid>
		<description><![CDATA[O comando eval Sinais de Processos Sinais assassinos O trap não atrapalha Comando getopts &#8211; E aê amigo, te dei a maior moleza, né? Um exerciciozinho muito simples&#8230;- É mais nos testes que eu fiz, e de acordo com o que você ensinou sobre substituição de parâmetros, achei que deveria fazer outras alterações nas funções [...]<img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=8&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></description>
			<content:encoded><![CDATA[<div class="twikiToc">
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo010#O_comando_eval"> O comando eval</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo010#Sinais_de_Processos"> Sinais de Processos</a>
<ul>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo010#Sinais_assassinos"> Sinais assassinos</a></li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo010#O_trap_n%C3%A3o_atrapalha"> O trap não atrapalha</a></li>
</ul>
</li>
<li> <a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo010#Comando_getopts"> Comando getopts</a></li>
</ul>
</div>
<hr />      &#8211; E aê amigo, te dei a maior moleza, né? Um exerciciozinho muito simples&#8230;- É mais nos testes que eu fiz, e de acordo com o que você ensinou sobre substituição de parâmetros, achei que deveria fazer outras alterações nas funções que desenvolvemos para torná-las de uso geral como você me disse que todas as funções deveriam ser, quer ver?- Claro né mané, se te pedi para fazer é porque estou afim de te ver aprender, mas peraí, dá um tempo!- Chico! Manda dois, um sem colarinho!- Vai, mostra aí o que você fez.- Bem, além do que você pediu, eu reparei que o programa que chamava a função, teria de ter previamente definidas a linha em que seria dada a mensagem e a quantidade de colunas. O que fiz foi incluir duas linhas &#8211; nas quais empreguei substituição de parâmetros &#8211; que caso uma destas variáveis não fosse informada, a própria função atribuiria. A linha de mensagem seria três linhas acima do fim da tela e o total de colunas seria obtido pelo comando tput cols. Veja como ficou:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat pergunta.func<font color="#ffffff"><br />
#  A funcao recebe 3 parametros na seguinte ordem:<br />
#  $1 &#8211; Mensagem a ser dada na tela<br />
#  $2 &#8211; Valor a ser aceito com resposta default<br />
#  $3 &#8211; O outro valor aceito<br />
#  Supondo que $1=Aceita?, $2=s e $3=n, a linha<br />
#  abaixo colocaria em Msg o valor &#8220;Aceita? (S/n)&#8221;<br />
TotCols=${TotCols:-$(tput cols)}   # Se nao estava definido, agora esta<br />
LinhaMesg=${LinhaMesg:-$(($(tput lines)-3))} # Idem<br />
Msg=&#8221;$1 (`echo $2 | tr a-z A-Z`/`echo $3 | tr A-Z a-z`)&#8221;<br />
TamMsg=${#Msg}<br />
Col=$(((TotCols &#8211; TamMsg) / 2))    # Para centrar Msg na linha<br />
tput cup $LinhaMesg $Col<br />
read -n1 -p &#8220;$Msg &#8221; SN<br />
SN=${SN:-$2}                       # Se vazia coloca default em SN<br />
SN=$(echo $SN | tr A-Z a-z)        # A saida de SN serah em minuscula<br />
tput cup $LinhaMesg $Col; tput el  # Apaga msg da tela</font></div>
<p>- Gostei, você já se antecipou ao que eu ia pedir. Só pra gente encerrar este papo de substituição de parâmetros, repare que a legibilidade está horrorível, mas a performance, isto é, velocidade de execução, está ótima. Como funções são coisas muito pessoais, já que cada um usa as suas, e quase não dão manutenção, eu sempre opto pela performance.</p>
<p>- Hoje vamos sair daquela chatura que foi o nosso último papo e vamos voltar à lógica saindo da decoreba, mas volto a te lembrar, tudo que eu te mostrei da outra vez aqui no Boteco do Chico é válido e quebra um galhão, guarde aqueles guardanapos que rabiscamos que, mais cedo ou mais tarde, vão te ser muito úteis.</p>
<h2><a title="O_comando_eval" name="O_comando_eval"></a> O comando eval</h2>
<p>- Vou te dar um problema que eu duvido que você resolva:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ var1=3<br />
$ var2=var1</div>
<p>- Te dei estas duas variáveis, e quero que você me diga como eu posso, só me referindo a <code>$var2</code>, listar o valor de <code>$var1</code> (<code>3</code>).</p>
<p>- A isso é mole, é só fazer:</p>
<pre>    echo $`echo $var2`</pre>
<p>- Repare que eu coloquei o echo <code>$var2</code> entre crases (<code>`</code>), que desta forma terá prioridade de execução e resultará em <code>var1</code>, montando <code>echo$var1</code> que produzirá <code>3</code>&#8230;</p>
<p>- A é? Então execute para ver se está correto.</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ echo $`echo $var2`<font color="#ffffff"><br />
$var1</font></div>
<p>- Ué! Que foi que houve? O meu raciocínio me parecia bastante lógico&#8230;</p>
<p>- O seu raciocínio realmente foi lógico, o problema é que você esqueceu de uma das primeiras coisas que te falei aqui no Boteco e vou repetir. O <i>Shell</i> usa a seguinte ordem para resolver uma linha de comandos:</p>
<ul>
<li> Resolve os redirecionamentos;</li>
<li> Substitui as variáveis pelos seus valores;</li>
<li> Resolve e substitui os meta caracteres;</li>
<li> Passa a linha já toda esmiuçada para execução.</li>
</ul>
<p>Desta forma, quando chegou na fase de resolução de variáveis, que como eu disse é anterior à execução, a única variável existente era <code>$var2</code> e por isso a tua solução produziu como saída <code>$var1</code>. O comando <code>echo</code> identificou isso como uma cadeia e não como uma variável.</p>
<p>Problemas deste tipo são relativamente freqüentes e seriam insolúveis caso não existisse a instrução <code>eval</code>, cuja sintaxe é:</p>
<pre>    eval cmd</pre>
<p>Onde <code>cmd</code> é uma linha de comando qualquer que você poderia inclusive executar direto no <i>prompt</i> do terminal. Quando você põe o <code>eval</code> na frente, no entanto, o que ocorre é que o <i>Shell</i> trata <code>cmd</code> como se seus dados fossem parâmetros do <code>eval</code> e em seguida o <code>eval</code> executa a linha recebida, submetendo-a ao <i>Shell</i>, dando então na prática duas passadas em <code>cmd</code>.</p>
<p>Desta forma se executássemos o comando que você propôs colocando o <code>eval</code> à sua frente, teríamos a saída esperada, veja:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ eval echo $`echo $var2`<font color="#ffffff"><br />
3</font></div>
<p>Este exemplo também poderia ter sido feito da seguinte maneira:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ eval echo $$var2<font color="#ffffff"><br />
3</font></div>
<p>Na primeira passada a contrabarra (<code></code>) seria retirada e <code>$var2</code> seria resolvido produzindo <code>var1</code>, para a segunda passada teria sobrado echo <code>$var1</code>, que produziria o resultado esperado.</p>
<p>Agora vou colocar um comando dentro de <code>var2</code>:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ var2=ls</div>
<p>Vou executar:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ $var2<font color="#ffffff"><br />
10porpag1.sh  alo2.sh       listamusica    logaute.sh<br />
10porpag2.sh  confuso       listartista    mandamsg.func<br />
10porpag3.sh  contpal.sh    listartista3   monbg.sh<br />
alo1.sh       incusu        logado</font></div>
<p>Agora vamos colocar em <code>var2</code> o seguinte: <code>ls $var1</code>; e em <code>var1</code> vamos colocar <code>l*</code>, vejamos:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ var2=&#8217;ls $var1&#8242;<br />
$ var1=&#8217;l*&#8217;<br />
$ $var2<font color="#ffffff"><br />
ls: $var1: No such file or directory</font><br />
$ eval $var2<font color="#ffffff"><br />
listamusica  listartista  listartista3  logado  logaute.sh</font></div>
<p>Novamente, no tempo de substituição das variáveis, <code>$var1</code> ainda não havia se apresentado ao <i>Shell</i> para ser resolvida, desta forma só nos resta executar o comando <code>eval</code> para dar as duas passadas necessárias.</p>
<p>Uma vez um colega de uma <a href="http://br.groups.yahoo.com/group/shell-script" target="_blank"><b>excelente lista sobre <i>Shell Script</i></b></a>, colocou uma dúvida: queria fazer um menu que numerasse e listasse todos os arquivos com extensão <code>.sh</code> e quando o operador escolhesse uma opção, o programa correspondente seria executado. A minha proposta foi a seguinte:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat fazmenu<font color="#ffffff"><br />
#!/bin/bash<br />
#<br />
# Lista numerando os programas com extensão .sh no<br />
# diretório corrente e executa o escolhido pelo operador<br />
#<br />
clear; i=1<br />
printf &#8220;%11st%snn&#8221; Opção Programa<br />
CASE=&#8217;case $opt in&#8217;<br />
for arq in *.sh<br />
do<br />
printf &#8220;t%03dt%sn&#8221; $i $arq<br />
CASE=&#8221;$CASE<br />
&#8220;$(printf &#8220;%03d)t %s;;&#8221; $i $arq)<br />
i=$((i+1))<br />
done<br />
CASE=&#8221;$CASE<br />
*)        . erro;;<br />
esac&#8221;<br />
read -n3 -p &#8220;Informe a opção desejada: &#8221; opt<br />
echo<br />
eval &#8220;$CASE&#8221;</font></div>
<p>Parece complicado porque usei muito <code>printf</code> para formatação da tela, mas é bastante simples, vamos entendê-lo: o primeiro <code>printf</code> foi colocado para fazer o cabeçalho e logo em seguida comecei a montar dinamicamente a variável <code>$CASE</code>, na qual ao final será feito um <code>eval</code> para execução do programa escolhido. Repare no entanto que dentro do <i>loop</i> do <code>for</code> existem dois <code>printf</code>: o primeiro serve para formatar a tela e o segundo para montar o <code>case</code> (se antes do comando <code>read</code> você colocar uma linha <code>echo "$CASE"</code>, verá que o comando <code>case</code> montado dentro da variável está todo indentado. Frescura, né? <img src='http://s0.wp.com/wp-includes/images/smilies/icon_smile.gif' alt=':)' class='wp-smiley' /> . Na saída do <code>for</code>, foi adicionada uma linha à variável <code>$CASE</code>, para no caso de se fazer uma opção inválida, ser executada uma função externa para dar mensagens de erro.</p>
<p>Vamos executá-lo para ver a saída gerada:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ fazmenu.sh<font color="#ffffff"><br />
Opcao     Programa<br />
</font><br />
<font color="#ffffff">        001     10porpag1.sh<br />
002     10porpag2.sh<br />
003     10porpag3.sh<br />
004     alo1.sh<br />
005     alo2.sh<br />
006     contpal.sh<br />
007     fazmenu.sh<br />
008     logaute.sh<br />
009     monbg.sh<br />
010     readpipe.sh<br />
011     redirread.sh<br />
Informe a opção desejada:</font></div>
<p>Neste programa seria interessante darmos uma opção de término, e para isso seria necessário a inclusão de uma linha após o <i>loop</i> de montagem da tela e alterarmos a linha na qual fazemos a atribuição final do valor da variável <code>$CASE</code>. Vejamos como ele ficaria:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat fazmenu<font color="#ffffff"><br />
#!/bin/bash<br />
#<br />
# Lista numerando os programas com extensão .sh no<br />
# diretório corrente e executa o escolhido pelo operador<br />
#<br />
clear; i=1<br />
printf &#8220;%11st%snn&#8221; Opção Programa<br />
CASE=&#8217;case $opt in&#8217;<br />
for arq in *.sh<br />
do<br />
printf &#8220;t%03dt%sn&#8221; $i $arq<br />
CASE=&#8221;$CASE<br />
&#8220;$(printf &#8220;%03d)t %s;;&#8221; $i $arq)<br />
i=$((i+1))<br />
done<br />
printf &#8220;t%dt%snn&#8221; 999 &#8220;Fim do programa&#8221;  # Linha incluida<br />
CASE=&#8221;$CASE<br />
999)        exit;;                       # Linha alterada<br />
*)        ./erro;;<br />
esac&#8221;<br />
read -n3 -p &#8220;Informe a opção desejada: &#8221; opt<br />
echo<br />
eval &#8220;$CASE&#8221;</font></div>
<h2><a title="Sinais_de_Processos" name="Sinais_de_Processos"></a> Sinais de Processos</h2>
<p>Existe no Linux uma coisa chamada sinal (<i>signal</i>). Existem diversos sinais que podem ser mandados para (ou gerados por) processos em execução. Vamos de agora em diante dar uma olhadinha nos sinais mandados para os processos e mais à frente vamos dar uma passada rápida pelos sinais gerados por processos.</p>
<h3><a title="Sinais_assassinos" name="Sinais_assassinos"></a> Sinais assassinos</h3>
<p>Para mandar um sinal a um processo, usamos normalmente o comando <code>kill</code>, cuja sintaxe é:</p>
<pre>    kill -sig PID</pre>
<p>Onde <code>PID</code> é o identificador do processo (<i><kbd>P</kbd>rocess <kbd>ID</kbd>entification</i> ou <i><kbd>P</kbd>rocess <kbd>ID</kbd></i>). Além do comando <code>kill</code>, algumas seqüências de teclas também podem gerar <code>sig</code>. A tabela a seguir mostra os sinais mais importantes para monitorarmos:</p>
<table class="twikiTable" border="0" cellpadding="2" cellspacing="1">
<tr>
<th colspan="3" class="twikiFirstCol" align="center" bgcolor="#000000"><b><font color="#ffffff">Sinais Mais Importantes</font></b></th>
</tr>
<tr>
<td colspan="2" class="twikiFirstCol" align="center" bgcolor="#ffffff"><b>Sinal</b></td>
<td bgcolor="#ffffff"><b> Gerado por:</b></td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff">0</td>
<td align="center" bgcolor="#ffffff">EXIT</td>
<td bgcolor="#ffffff">Fim normal do programa</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff">1</td>
<td align="center" bgcolor="#ffffff">SIGHUP</td>
<td bgcolor="#ffffff">Quando recebe um kill -HUP</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff">2</td>
<td align="center" bgcolor="#ffffff">SIGINT</td>
<td bgcolor="#ffffff">Interrupção pelo teclado (&lt;CTRL+C&gt;)</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff">3</td>
<td align="center" bgcolor="#ffffff">SIGQUIT</td>
<td bgcolor="#ffffff">Interrupção pelo teclado (&lt;CTRL+&gt;)</td>
</tr>
<tr>
<td class="twikiFirstCol" align="center" bgcolor="#ffffff">15</td>
<td align="center" bgcolor="#ffffff">SIGTERM</td>
<td bgcolor="#ffffff">Quando recebe um kill ou kill -TERM</td>
</tr>
</table>
<p>Além destes sinais, existe o famigerado <code>-9</code> ou <code>SIGKILL</code> que, para o processo que o está recebendo, equivale a meter o dedo no botão de desliga do computador o que seria altamente indesejável já que muitos programas necessitam &#8220;limpar o meio de campo&#8221; ao seu término. Se o seu final ocorrer de forma prevista, ou seja se tiver um término normal, é muito fácil de fazer esta limpeza, porém se o seu programa tiver um fim brusco muita coisa pode ocorrer:</p>
<ul>
<li> É possível que em um determinado espaço de tempo, o seu computador esteja cheio de arquivos de trabalho inúteis</li>
<li> Seu processador poderá ficar atolado de processos <i>zombies</i> e <i>defuncts</i> gerados por processos filhos que perderam os pais;</li>
<li> É necessário liberar <i>sockets</i> abertos para não deixar os clientes congelados;</li>
<li> Seus bancos de dados poderão ficar corrompidos porque sistemas gerenciadores de bancos de dados necessitam de um tempo para gravar seus <i>buffers</i> em disco (<i>commit</i>).</li>
</ul>
<p>Enfim, existem mil razões para não usar um <code>kill</code> com o sinal <code>-9</code> e para monitorar fins anormais de programas.</p>
<h3><a title="O_trap_não_atrapalha" name="O_trap_não_atrapalha"></a> O trap não atrapalha</h3>
<p>Para fazer a monitoração descrita acima existe o comando <code>trap</code> cuja sintaxe é:</p>
<pre>    trap "cmd1; cmd2; cmdn" S1 S2 ... SN</pre>
<p>ou</p>
<pre>    trap 'cmd1; cmd2; cmdn' S1 S2 ... SN</pre>
<p>Onde os comandos <code>cmd1</code>, <code>cmd2</code>, <code>cmdn</code> serão executados caso o programa receba os sinais <code>S1 S2</code> &#8230; <code>SN</code>.</p>
<p>As aspas (&#8220;) ou os apóstrofos (&#8216;) só são necessários caso o <code>trap</code> possua mais de um comando <code>cmd</code> associado. Cada um dos <code>cmd</code> pode ser também uma função interna, uma externa ou outro <i>script</i>.</p>
<p>Para entender o uso de aspas (&#8220;) e apóstrofos (&#8216;) vamos recorrer a um exemplo que trata um fragmento de um <i>script</i> que faz um <code>ftp</code> para uma máquina remota (<code>$RemoComp</code>), na qual o usuário é <code>$Fulano</code>, sua senha é <code>$Segredo</code> e vai transmitir o arquivo contido em <code>$Arq</code>. Suponha ainda que estas quatro variáveis foram recebidas em uma rotina anterior de leitura e que este <i>script</i> é muito usado por diversas pessoas da instalação. Vejamos este trecho de código:</p>
<pre>ftp -ivn $RemoComp &lt;&lt; FimFTP &gt;&gt; /tmp/$$ 2&gt;&gt; /tmp/$$
    user $Fulano $Segredo
    binary
    get $Arq
FimFTP</pre>
<p>Repare que, tanto as saídas do dos diálogos do <code>ftp</code>, como os erros encontrados, estão sendo redirecionados para <code>/tmp/$$</code>, o que é uma construção bastante normal para arquivos temporários usados em <i>scripts</i> com mais de um usuário, porque <code>$$</code> é a variável que contém o número do processo (<code>PID</code>), que é único, e com este tipo de construção evita-se que dois ou mais usuários disputem a posse e os direitos sobre o arquivo.</p>
<p>Caso este <code>ftp</code> seja interrompido por um <code>kill</code> ou um <code>&lt;CTRL+C&gt;</code>, certamente deixará lixo no disco. É exatamente esta a forma como mais se usa o comando <code>trap</code>. Como isto é trecho de um <i>script</i>, devemos, logo no seu início, como um de seus primeiros comandos, fazer:</p>
<pre>    trap "rm -f /tmp/$$ ; exit" 0 1 2 3 15</pre>
<p>Desta forma, caso houvesse uma interrupção brusca (sinais <code>1</code>, <code>2</code>, <code>3</code> ou <code>15</code>) antes do programa encerrar (no <code>exit</code> dentro do comando <code>trap</code>), ou um fim normal (sinal <code>0</code>), o arquivo <code>/tmp/$$</code> seria removido.</p>
<p>Caso na linha de comandos do <code>trap</code> não houvesse a instrução <code>exit</code>, ao final da execução desta linha o fluxo do programa retornaria ao ponto em que estava quando recebeu o sinal que originou a execução deste <code>trap</code>.</p>
<p>Este <code>trap</code> poderia ser subdividido, ficando da seguinte forma:</p>
<pre>    trap "rm -f /tmp/$$" 0
    trap "exit" 1 2 3 15</pre>
<p>Assim ao receber um dos sinais o programa terminaria, e ao terminar, geraria um sinal <code>0</code>, que removeria o arquivo. Caso seu fim seja normal, o sinal também será gerado e o <code>rm</code> será executado.</p>
<p>Note também que o <i>Shell</i> pesquisa a linha de comandos uma vez quanto o <code>trap</code> é interpretado (e é por isso que é usual colocá-lo no início do programa) e novamente quando um dos sinais listados é recebido. Então, no último exemplo, o valor de <code>$$</code> será substituído no momento que o comando <code>trap</code> foi lido da primeira vez, já que as aspas (<code>"</code>) não protegem o cifrão (<code>$</code>) da interpretação do <i>Shell</i>.</p>
<p>Se você desejasse que a substituição fosse realizada somente quando recebesse o sinal, o comando deveria ser colocado entre apóstrofos (<code>'</code>). Assim, na primeira interpretação do <code>trap</code>, o <i>Shell</i> não veria o cifrão (<code>$</code>), porém os apóstrofos (<code>'</code>) seriam removidos e finalmente o <i>Shell</i> poderia substituir o valor da variável. Neste caso, a linha ficaria da seguinte maneira:</p>
<pre>    trap 'rm -f /tmp/$$ ; exit' 0 1 2 3 15</pre>
<p>Suponha dois casos: você tem dois <i>scripts</i> que chamaremos de <code>script1</code>, cuja primeira linha será um <code>trap</code> e <code>script2</code>, sendo este último colocado em execução pelo primeiro, e por serem dois processos, terão dois <code>PID</code> distintos.</p>
<ul>
<li> 1º Caso: O <code>ftp</code> encontra-se em <code>script1</code><br />
Neste caso, o argumento do comando <code>trap</code> deveria vir entre aspas (<code>"</code>) porque caso ocorresse uma interrupção (<code>&lt;CTRL+C&gt;</code> ou <code>&lt;CTRL+&gt;</code>) no <code>script2</code>, a linha só seria interpretada neste momento e o <code>PID</code> do <code>script2</code> seria diferente do encontrado em <code>/tmp/$$</code> (não esqueça que <code>$$</code> é a variável que contém o <code>PID</code> do processo ativo);</li>
</ul>
<ul>
<li> 2º Caso: O <code>ftp</code> acima encontra-se em <code>script2</code><br />
Neste caso, o argumento do comando <code>trap</code> deveria estar entre apóstrofos (<code>'</code>), pois caso a interrupção se desse durante a execução de <code>script1</code>, o arquivo não teria sido criado, caso ocorresse durante a execução de <code>script2</code>, o valor de <code>$$</code> seria o <code>PID</code> deste processo, que coincidiria com o de <code>/tmp/$$</code>.</li>
</ul>
<p>O comando <code>trap</code>, quando executado sem argumentos, lista os sinais que estão sendo monitorados no ambiente, bem como a linha de comando que será executada quando tais sinais forem recebidos.</p>
<p>Se a linha de comandos do <code>trap</code> for nula (vazia), isto significa que os sinais especificados devem ser ignorados quando recebidos. Por exemplo, o comando:</p>
<pre>    trap "" 2</pre>
<p>Especifica que o sinal de interrupção (<code>&lt;CTRL+C&gt;</code>) deve ser ignorado. No caso citado, quando não se deseja que sua execução seja interrompida. No último exemplo note que o primeiro argumento deve ser especificado para que o sinal seja ignorado, e não é equivalente a escrever o seguinte, cuja finalidade é retornar o sinal <code>2</code> ao seu estado padrão (<i>default</i>):</p>
<pre>    trap 2</pre>
<p>Se você ignora um sinal, todos os <i>Subshells</i> irão ignorar este sinal. Portanto, se você especifica qual ação deve ser tomada quando receber um sinal, então todos os <i>Subshells</i> irão também tomar a ação quando receberem este sinal, ou seja, os sinais são automaticamente exportados. Para o sinal que temos mostrado (sinal <code>2</code>), isto significa que os Subshells serão encerrados.</p>
<p>Suponha que você execute o comando:</p>
<pre>    trap "" 2</pre>
<p>e então execute um <i>Subshell</i>, que tornará a executar outro <i>script</i> como um <i>Subshell</i>. Se for gerado um sinal de interrupção, este não terá efeito nem sobre o <i>Shell</i> principal nem sobre os <i>Subshell</i> por ele chamados, já que todos eles ignorarão o sinal.</p>
<p>Outra forma de restaurar um sinal ao seu default é fazendo:</p>
<pre>    trap - sinal</pre>
<p>Em <i>korn shell</i> (<code>ksh</code>) não existe a opção <code>-s</code> do comando <code>read</code> para ler uma senha. O que costumamos fazer é usar o comando <code>stty</code> com a opção <code>-echo</code> que inibe a escrita na tela até que se encontre um <code>stty echo</code> para restaurar esta escrita. Então, se estivéssemos usando o interpretador <code>ksh</code>, a leitura da senha teria que ser feita da seguinte forma:</p>
<pre>    echo -n "Senha: "
    stty -echo
    read Senha
    stty echo</pre>
<p>O problema neste tipo de construção é que caso o operador não soubesse a senha, ele provavelmente daria um <code>&lt;CTRL+C&gt;</code> ou um <code>&lt;CTRL+&gt;</code> durante a instrução <code>read</code> para descontinuar o programa e, caso ele agisse desta forma, o que quer que ele escrevesse, não apareceria na tela do seu terminal. Para evitar que isso aconteça, o melhor a fazer é:</p>
<pre>    echo -n "Senha: "
    trap "stty echo
          exit" 2 3
    stty -echo
    read Senha
    stty echo
    trap 2 3</pre>
<p>Para terminar este assunto, abra uma console gráfica e escreva no prompt de comando o seguinte:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ trap &#8220;echo Mudou o tamanho da janela&#8221; 28</div>
<p>Em seguida, pegue o <i>mouse</i> (arghh!!) e arraste-o de forma a variar o tamanho da janela corrente. Surpreso? É o Shell orientado a eventos&#8230; <img src="http://twiki.softwarelivre.org/pub/TWiki/SmiliesPlugin/smile.gif" alt="smile" border="0" /></p>
<p>Mais unzinho porque não pude resistir. Agora escreva assim:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ trap &#8220;echo já era&#8221; 17</div>
<p>Em seguida faça:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ sleep 3 &amp;</div>
<p>Você acabou de criar um <i>subshell</i> que irá dormir durante três segundos em <i>background</i>. Ao fim deste tempo, você receberá a mensagem <code>já era</code>, porque o sinal <code>17</code> é emitido a cada vez que um <i>subshell</i> termina a sua execução.</p>
<p>Para devolver estes sinais aos seus defaults, faça:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ trap 17 28</div>
<p>Ou</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ trap &#8211; 17 28</div>
<p>Acabamos de ver mais dois sinais que não são tão importante como os que vimos anteriormente, mas vou registrá-los na tabela a seguir:</p>
<table class="twikiTable" border="0" cellpadding="2" cellspacing="1">
<tr>
<th colspan="3" class="twikiFirstCol" align="center" bgcolor="#000000"><b><font color="#ffffff">Sinais Não Muito Importantes</font></b></th>
</tr>
<tr>
<td colspan="2" class="twikiFirstCol" align="center" bgcolor="#ffffff"><b>Sinal</b></td>
<td bgcolor="#ffffff"><b> Gerado por:</b></td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#ffffff">17</td>
<td bgcolor="#ffffff">SIGCHLD</td>
<td bgcolor="#ffffff">Fim de um processo filho</td>
</tr>
<tr>
<td class="twikiFirstCol" bgcolor="#ffffff">28</td>
<td bgcolor="#ffffff">SIGWINCH</td>
<td bgcolor="#ffffff">Mudança no tamanho da janela gráfica</td>
</tr>
</table>
<p>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.</p>
<h2><a title="Comando_getopts" name="Comando_getopts"></a> Comando getopts</h2>
<p>O comando <code>getopts</code> recupera as opções e seus argumentos de uma lista de parâmetros de acordo com a sintaxe POSIX.2, isto é, letras (ou números) após um sinal de menos (<code>-</code>) seguidas ou não de um argumento; no caso de somente letras (ou números) elas podem ser agrupadas. Você deve usar este comando para &#8220;fatiar&#8221; opções e argumento passados para o seu <i>script</i>.</p>
<p>Sintaxe:</p>
<pre>    getopts cadeiadeopcoes nome</pre>
<p>A <code>cadeiadeopcoes</code> deve explicitar uma cadeia de caracteres com todas as opções reconhecidas pelo <i>script</i>, assim se ele reconhece as opções <code>-a</code> <code>-b</code> e <code>-c</code>, <code>cadeiadeopcoes</code> deve ser <code>abc</code>. Se você deseja que uma opção seja seguida por um argumento, ponha dois-pontos (<code>:</code>) depois da letra, como em <code>a:bc</code>. Isto diz ao <code>getopts</code> que a opção <code>-a</code> tem a forma:</p>
<pre>    -a argumento</pre>
<p>Normalmente um ou mais espaços em branco separam o parâmetro da opção; no entanto, <code>getopts</code> também manipula parâmetros que vêm colados à opção como em:</p>
<pre>    -aargumento</pre>
<p><code>cadeiadeopcoes</code> não pode conter interrogação (<code>?</code>).</p>
<p>O <code>nome</code> constante da linha de sintaxe acima, define uma variável que cada vez que o comando <code>getopts</code> for executado, receberá a próxima opção dos parâmetros posicionais e a colocará na variável <code>nome</code>.</p>
<p><code>getopts</code> coloca uma interrogação (<code>?</code>) na variável definida em <code>nome</code> se achar uma opção não definida em <code>cadeiadeopcoes</code> ou se não achar o argumento esperado para uma determinada opção.</p>
<p>Como já sabemos, cada opção passada por uma linha de comandos tem um índice numérico, assim, a primeira opção estará contida em <code>$1</code>, a segunda em <code>$2</code>, e assim por diante. Quando o <code>getopts</code> obtém uma opção, ele armazena o índice do próximo parâmetro a ser processado na variável <code>OPTIND</code>.</p>
<p>Quando uma opção tem um argumento associado (indicado pelo <code>:</code> na <code>cadeiadeopcoes</code>), <code>getopts</code> armazena o argumento na variável <code>OPTARG</code>. Se uma opção não possui argumento ou o argumento esperado não foi encontrado, a variável <code>OPTARG</code> será &#8220;matada&#8221; (<code>unset</code>).</p>
<p>O comando encerra sua execução quando:</p>
<ul>
<li> Encontra um parâmetro que não começa por menos (<code>-</code>);</li>
<li> O parâmetro especial <code>--</code> marca o fim das opções;</li>
<li> Quando encontra um erro (por exemplo, uma opção não reconhecida).</li>
</ul>
<p>O exemplo abaixo é meramente didático, servindo para mostrar, em um pequeno fragmento de código o uso pleno do comando.</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ cat getoptst.sh<font color="#ffffff"><br />
#!/bin/sh<br />
</font><br />
<font color="#ffffff"># Execute assim:<br />
#<br />
#       getoptst.sh -h -Pimpressora arq1 arq2<br />
#<br />
# e note que as informacoes de todas as opcoes sao exibidas<br />
#<br />
# A cadeia &#8216;P:h&#8217; diz que a opcao -P eh uma opcao complexa<br />
# e requer um argumento, e que h eh uma opcao simples que nao requer<br />
# argumentos.<br />
</font><br />
<font color="#ffffff">while getopts &#8216;P:h&#8217; OPT_LETRA<br />
do<br />
echo &#8220;getopts fez a variavel OPT_LETRA igual a &#8216;$OPT_LETRA&#8217;&#8221;<br />
echo &#8221;  OPTARG eh &#8216;$OPTARG&#8217;&#8221;<br />
done<br />
used_up=`expr $OPTIND &#8211; 1`<br />
echo &#8220;Dispensando os primeiros $OPTIND-1 = $used_up argumentos&#8221;<br />
shift $used_up<br />
echo &#8220;O que sobrou da linha de comandos foi &#8216;$*&#8217;&#8221;</font></div>
<p>Para entendê-lo melhor, vamos executá-lo como está sugerido em seu cabeçalho:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ getoptst.sh -h -Pimpressora arq1 arq2<font color="#ffffff"><br />
getopts fez a variavel OPT_LETRA igual a &#8216;h&#8217;<br />
OPTARG eh &#8221;<br />
getopts fez a variavel OPT_LETRA igual a &#8216;P&#8217;<br />
OPTARG eh &#8216;impressora&#8217;<br />
Dispensando os primeiros $OPTIND-1 = 2 argumentos<br />
O que sobrou da linha de comandos foi &#8216;arq1 arq2&#8242;</font></div>
<p>Desta forma, sem ter muito trabalho, separei todas as opções com seus respectivos argumentos, deixando somente os parâmetros que foram passados pelo operador para posterior tratamento.</p>
<p>Repare que se tivéssemos escrito a linha de comando com o argumento (<code>impressora</code>) separado da opção (<code>-P</code>), o resultado seria exatamente o mesmo, exceto pelo <code>$OPTIND</code>, já que neste caso ele identifica um conjunto de três opções/argumentos e no anterior somente dois. Veja só:</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ getoptst.sh -h -P impressora arq1 arq2<font color="#ffffff"><br />
getopts fez a variavel OPT_LETRA igual a &#8216;h&#8217;<br />
OPTARG eh &#8221;<br />
getopts fez a variavel OPT_LETRA igual a &#8216;P&#8217;<br />
OPTARG eh &#8216;impressora&#8217;<br />
Dispensando os primeiros $OPTIND-1 = 3 argumentos<br />
O que sobrou da linha de comandos foi &#8216;arq1 arq2&#8242;</font></div>
<p>Repare, no exemplo a seguir, que se passarmos uma opção inválida, a variável <code>$OPT_LETRA</code> receberá um ponto-de-interrogação (<code>?</code>) e a <code>$OPTARG</code> será &#8220;apagada&#8221; (<code>unset</code>).</p>
<div style="border:1px none;background:#000000 none no-repeat scroll right top;overflow:auto;font-family:Courier,'Courier New','Lucida Console','Bitstream Vera Sans Mono',Monaco,monospace;white-space:pre;font-size:100%;line-height:1em;color:yellow;margin:1em 0.5em;padding:1.5em 1em;">$ getoptst.sh -f -Pimpressora arq1 arq2  #  A opção �f não é valida<font color="#ffffff"><br />
./getoptst.sh: illegal option &#8212; f<br />
getopts fez a variavel OPT_LETRA igual a &#8216;?&#8217;<br />
OPTARG eh &#8221;<br />
getopts fez a variavel OPT_LETRA igual a &#8216;P&#8217;<br />
OPTARG eh &#8216;impressora&#8217;<br />
Dispensando os primeiros $OPTIND-1 = 2 argumentos<br />
O que sobrou da linha de comandos foi &#8216;arq1 arq2&#8242;</font></div>
<p>- Me diz uma coisa: você não poderia ter usado um <code>case</code> para evitar o <code>getopts</code>?</p>
<p>- Poderia sim, mas para que? Os comandos estão aí para serem usados&#8230; O exemplo dado foi didático, mas imagine um programa que aceitasse muitas opções e seus parâmetros poderiam ou não estar colados às opções, suas opções também poderiam ou não estar coladas, ia ser um <code>case</code> infernal e com <code>getopts</code> é só seguir os passos acima.</p>
<p>- É&#8230; Vendo desta forma acho que você tem razão. É porque eu já estou meio cansado com tanta informação nova na minha cabeça. Vamos tomar a saideira ou você ainda quer explicar alguma particularidade do <i>Shell</i>?</p>
<p>- Nem um nem outro, eu também já cansei mas hoje não vou tomar a saideira porque estou indo dar aula na UniRIO, que é a primeira universidade federal que está preparando no uso de Software Livre, seus alunos do curso de graduação em informática.</p>
<p>Mas antes vou te deixar um problema para te encucar: quando você varia o tamanho de uma tela, no seu centro não aparece dinamicamente em vídeo reverso a quantidade de linhas e colunas? Então! Eu quero que você reproduza isso usando a linguagem <i>Shell</i>.</p>
<p>- Chico, traz rapidinho a minha conta! Vou contar até um e se você não trouxer eu me mando!</p>
<p>Vou aproveitar também para mandar o meu jabá: diga para os amigos que quem estiver afim de fazer um curso porreta de programação em <i>Shell</i> que mande um e-mail para a nossa <a href="mailto:treinamentos@festivalsoftwarelivre.org?Subject=Curso%20de%20Shell%20com%20Julio%20Neves">gerencia de treinamento</a> para informar-se.</p>
<p>Qualquer dúvida ou falta de companhia para um chope ou até para falar mal dos políticos é só mandar um e-mail para <a href="mailto:julioneves@openoffice.org?Subject=D%C3%BAvidas%20Papo%20de%20Botequim">mim</a>.</p>
<p>Valeu!</p>
<br /><img alt="" border="0" src="http://feeds.wordpress.com/1.0/categories/jneves.wordpress.com/8/" /> <img alt="" border="0" src="http://feeds.wordpress.com/1.0/tags/jneves.wordpress.com/8/" /> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gocomments/jneves.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/comments/jneves.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godelicious/jneves.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/delicious/jneves.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gofacebook/jneves.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/facebook/jneves.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gotwitter/jneves.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/twitter/jneves.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/gostumble/jneves.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/stumble/jneves.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/godigg/jneves.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/digg/jneves.wordpress.com/8/" /></a> <a rel="nofollow" href="http://feeds.wordpress.com/1.0/goreddit/jneves.wordpress.com/8/"><img alt="" border="0" src="http://feeds.wordpress.com/1.0/reddit/jneves.wordpress.com/8/" /></a> <img alt="" border="0" src="http://stats.wordpress.com/b.gif?host=jneves.wordpress.com&amp;blog=3067756&amp;post=8&amp;subd=jneves&amp;ref=&amp;feed=1" width="1" height="1" />]]></content:encoded>
			<wfw:commentRss>http://jneves.wordpress.com/2008/03/05/8/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
	
		<media:content url="http://1.gravatar.com/avatar/53f0649d2d6a9b19b90abd0575ee5c7c?s=96&#38;d=identicon&#38;r=G" medium="image">
			<media:title type="html">jneves</media:title>
		</media:content>

		<media:content url="http://twiki.softwarelivre.org/pub/TWiki/SmiliesPlugin/smile.gif" medium="image">
			<media:title type="html">smile</media:title>
		</media:content>
	</item>
	</channel>
</rss>
