<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Shell on Peczenyj's Blog</title><link>http://pacman.blog.br/categories/shell/</link><description>Recent content in Shell on Peczenyj's Blog</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Wed, 18 Jun 2008 15:15:00 -0300</lastBuildDate><atom:link href="http://pacman.blog.br/categories/shell/atom.xml" rel="self" type="application/rss+xml"/><item><title>Tabela do Brasileirão 2008 com links + sed</title><link>http://pacman.blog.br/blog/2008/06/18/tabela-do-brasileiro-2008-com-links-sed/</link><pubDate>Wed, 18 Jun 2008 15:15:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2008/06/18/tabela-do-brasileiro-2008-com-links-sed/</guid><description>&lt;div class='post'>
O sed é um processador de texto muito versátil.&lt;br />&lt;br />O links é um browser modo texto com features tão interessantes quanto do antigo lynx.&lt;br />&lt;br />Ano passado eu &lt;a href="http://peczenyj.blogspot.com/2007/06/classificao-do-brasileiro-via-shell.html">postei&lt;/a> como imprimir a tabela do brasileirão com um one liner interessante. Agora eu resolvi beber de outra fonte:&lt;br />&lt;br />&lt;pre>&lt;code>#!/bin/bash&lt;br />TIME=Internacional&lt;br />COLOR=$(echo -ne '\e[31;1m&amp;\e[m')&lt;br />URL=http://globoesporte.globo.com/Esportes/Futebol/Classificacao/0,,ESP0-9827,00.html&lt;br />links --dump ${URL} | sed -r 's/\[[0-9]*\]//;/(^[0-9]|J jogos)/!d' | sed "s/${TIME}/${COLOR}/&lt;br /> 1a-----Libertadores----------&lt;br /> 4a-----Pre-Libertadores------&lt;br /> 5a-----Sul-Americana---------&lt;br /> 13a---------------------------&lt;br /> 17a-----Rebaixado-------------"&lt;/pre>&lt;/code>&lt;br />&lt;br />O resultado não é tão bom quanto o do ano passado, é verdade, mas não deixa de ser uma alternativa&lt;/div>
&lt;h2>Comments&lt;/h2>
&lt;div class='comments'>
&lt;div class='comment'>
&lt;div class='author'>Alan Carvalho de Assis&lt;/div>
&lt;div class='content'>
Ola Tiago,&lt;BR/>gostei do script, muito fera.&lt;BR/>&lt;BR/>Um abraço,&lt;BR/>&lt;BR/>Alan&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Tiago Peczenyj&lt;/div>
&lt;div class='content'>
Dê tempo ao tempo... ;-)&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Ivan Brasil Fuzzer&lt;/div>
&lt;div class='content'>
Com poucas alterações no script até o resultado melhora.&lt;BR/>Os bugs encontrados estão na cor e no time!&lt;BR/>Mudando para azul e Gremio fica bem melhor :-P&lt;BR/>&lt;BR/>Abraços.&lt;/div>
&lt;/div>
&lt;/div></description></item><item><title>Pesquisando nos Grupos do Yahoo</title><link>http://pacman.blog.br/blog/2008/05/28/pesquisando-nos-grupos-do-yahoo/</link><pubDate>Wed, 28 May 2008 18:17:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2008/05/28/pesquisando-nos-grupos-do-yahoo/</guid><description>&lt;div class='post'>
Meu amigo MrBits me deu essa grande ideia:&lt;br />&lt;br />&lt;pre>&lt;code>#!/bin/bash&lt;br />QTDE=20&lt;br />CHARSET=UTF-8&lt;br />GROUP=shell-script&lt;br />&lt;br />while getopts g:c:q: OPTION ; do&lt;br /> case $OPTION in&lt;br /> g) GROUP=$OPTARG ;;&lt;br /> c) CHARSET=$OPTARG ;;&lt;br /> q) QTDE=$OPTARG ;;&lt;br /> esac&lt;br />done&lt;br />&lt;br />shift $(($OPTIND -1))&lt;br />&lt;br />SEARCH="$@"&lt;br />&lt;br />if [ -z "$SEARCH" ]; then &lt;br /> echo "Usage: $(basename $0) [-q qtde] [-g grupo] [-c charset] search" &lt;br /> exit 1&lt;br />fi&lt;br />&lt;br />BASEURL="http://br.groups.yahoo.com/group"&lt;br />URL="${BASEURL}/${GROUP}/msearch?submit=OK&amp;charset=${CHARSET}&amp;cnt=${QTDE}&amp;query=${SEARCH// /+}" &lt;br />SEDCMD="/message/!d;/${GROUP}/!d;/.*[0-9]/!d;s#/group#${BASEURL}#g;s/&lt;[^>]*span>//g;s/$/&amp;lt;br \/&amp;gt;/"&lt;br />&lt;br />LYNXOPT="-dump -force_html -assume_charset=${CHARSET}"&lt;br />lynx $LYNXOPT &lt;( curl -b /tmp/cookie$$ -sL "${URL}" | sed "${SEDCMD}" )&lt;/code>&lt;/pre>&lt;br />&lt;br />Vejamos em uso:&lt;br />&lt;pre>$ ./find.sh &lt;br />Usage: find.sh [-q qtde] [-g grupo] [-c charset] search&lt;br />&lt;br />$ ./find.sh -q 10 getopts # procurando por getopts limitando a 10 registros&lt;br /> [1]Re: [shell-script] Script de busca de mensagens&lt;br /> [2]Re: [shell-script] Re: script iterativo / passo a passo&lt;br /> [3]Re: [shell-script] Script de Backup&lt;br /> [4]Re: [shell-script] Script de Backup&lt;br /> [5]Re: [shell-script] Script de Backup&lt;br /> [6]Re: [shell-script] Script de Backup&lt;br /> [7]Re: [shell-script] Echo e executa: superecho&lt;br /> [8]Re: [shell-script] testar se parametro $1 foi passado&lt;br /> [9]Re: [shell-script] Echo e executa: superecho&lt;br /> [10]Re: [shell-script] testar se parametro $1 foi passado&lt;br />&lt;br />References&lt;br />&lt;br /> 1. http://br.groups.yahoo.com/group/shell-script/message/26373&lt;br /> 2. http://br.groups.yahoo.com/group/shell-script/message/26204&lt;br /> 3. http://br.groups.yahoo.com/group/shell-script/message/26078&lt;br /> 4. http://br.groups.yahoo.com/group/shell-script/message/26076&lt;br /> 5. http://br.groups.yahoo.com/group/shell-script/message/26075&lt;br /> 6. http://br.groups.yahoo.com/group/shell-script/message/26072&lt;br /> 7. http://br.groups.yahoo.com/group/shell-script/message/25742&lt;br /> 8. http://br.groups.yahoo.com/group/shell-script/message/25720&lt;br /> 9. http://br.groups.yahoo.com/group/shell-script/message/25719&lt;br /> 10. http://br.groups.yahoo.com/group/shell-script/message/25718&lt;/pre>&lt;br />&lt;br />Divertido, não? o default é procurar no grupo shell-script do yahoo, mas ele pode investigar em qualquer um.&lt;br />&lt;br />Valeu Mr.Bits!!&lt;/div>
&lt;h2>Comments&lt;/h2>
&lt;div class='comments'>
&lt;div class='comment'>
&lt;div class='author'>Tiago Peczenyj&lt;/div>
&lt;div class='content'>
Hahaha... te amarrou, gc?&lt;BR/>&lt;BR/>Podes usar pra pesquisar no rioguj ;-)&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Guilherme Chapiewski&lt;/div>
&lt;div class='content'>
\o/&lt;BR/>&lt;BR/>É por isso que bash é a melhor coisa de todo o universo!!!&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Tiago Peczenyj&lt;/div>
&lt;div class='content'>
Mas é facil, Roger!&lt;BR/>&lt;BR/>/padrão/!d -> apaga *todas* as linhas que *não* casam com o padrão&lt;BR/>&lt;BR/>s/padrão/substituição/g -> substitui, globalmente, o padrão pela substituição&lt;BR/>&lt;BR/>s#xxx#yyy#g -> mesma coisa, util para não ter que escapar o caracter /&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Roger Leite&lt;/div>
&lt;div class='content'>
Putz Tiago ! Você tá ficando muito louco mesmo, deve ser o sol ai do Rio ... não é possível !&lt;BR/>&lt;BR/>Estes comandos de sed são de arrepiar, um dia ainda vou entender isso "nativo".&lt;BR/>&lt;BR/>flw e sucesso!&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Tiago Peczenyj&lt;/div>
&lt;div class='content'>
VB ? NUNCA!!!&lt;BR/>&lt;BR/>Mas ja fiz coisas com VBScript... :$&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Marcelo Martins&lt;/div>
&lt;div class='content'>
Tiago, tu ta ficando cada vez pior cara. Já pensou em dar um tempo e programar um pouco em Visual Basic?&lt;BR/>&lt;BR/>&lt;BR/>hehe.. muito bom!&lt;/div>
&lt;/div>
&lt;/div></description></item><item><title>Manipulando logs com AWK e SED</title><link>http://pacman.blog.br/blog/2008/04/26/manipulando-logs-com-awk-e-sed/</link><pubDate>Sat, 26 Apr 2008 14:41:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2008/04/26/manipulando-logs-com-awk-e-sed/</guid><description>&lt;div class='post'>
Eis que a lista de &lt;a href="http://br.groups.yahoo.com/group/shell-script/">shell script&lt;/a> traz um bom desafio.&lt;br />&lt;br />&lt;cite>Galera, tenho o seguinte log.:&lt;br />&lt;br />AAAA-------------campo_1-------------campo_2-----campo_3----campo_4---------- &lt;br />teste_1 371508787 371547453 38666 testetesteteste&lt;br />&lt;br />BBBB-------------campo_1-------------campo_2-----campo_3----campo_4---------- &lt;br />teste_2 4625081503 4651313710 26232207 testetesteteste&lt;br />&lt;br />Estou a tentar usar o awk com a seguinte função : &lt;br />awk '$1~"teste_" {print $5";"$4}' teste > teste_.csv&lt;br />&lt;br />a funcao busca realmente o que desejo:&lt;br />$5 $4&lt;br />testetesteteste 38666&lt;br />testetesteteste 6232207&lt;br />&lt;br />porem,, gostaria que seprasse da forma:&lt;br />&lt;br />AAAA------------- &lt;br />testetesteteste 38666 &lt;br />BBBB------------- &lt;br />testetesteteste 26232207 &lt;br />&lt;br />Alguém tem uma dica de como fazer?&lt;/cite>&lt;br />&lt;br />Ah... o bom e velho &lt;span style="font-weight:bold;">SED&lt;/span> pode resolver isso&lt;br />&lt;br />&lt;code>$ sed -rn '/(^[^-]+-+).*/{s//\1/;h};&lt;br />/^teste_/{s/.* ([^ ]+) +([^ ]+$)/\2 \1/;x;p;g;p}' arquivo.log&lt;br />AAAA-------------&lt;br />testetesteteste 38666&lt;br />BBBB-------------&lt;br />testetesteteste 26232207&lt;/code>&lt;br />&lt;br />Ok, ok, ta muito complicado, mas veja só:&lt;br />&lt;br />&lt;code>$ sed -rn '/^[^-]+-+/h;/^teste_/{x;p;g;p}' arquivo.log &lt;br />AAAA-------------campo_1-------------campo_2-----campo_3----campo_4----------&lt;br />teste_1 371508787 371547453 38666 testetesteteste&lt;br />BBBB-------------campo_1-------------campo_2-----campo_3----campo_4----------&lt;br />teste_2 4625081503 4651313710 26232207 testetesteteste&lt;/code>&lt;br />&lt;br />Vamos explicar&lt;br />1) a opção -n serve para informar ao sed "imprima apenas quando eu mandar"&lt;br />2) a opção -p serve para utilizar expressões regulares extendidas&lt;br />(assim não preciso escapar o quantificador + , que significa "um ou&lt;br />mais vezes", assim como os parentesis, para informar os grupos).&lt;br />&lt;br />Eu fiz uma sacanagem. o comando h quarda o padrão num espaço chamado espaço reserva, tipo uma memória do sed, sobreescrevendo. Assim no espaço reserva eu tenho a ultima ocorrencia de uma linha do tipo, ^[^-]+-+ ,que traduzindo significa: tudo o que começa com um ou varios caracteres diferentes de -, seguidos de um ou varios - (no caso&lt;br />do AAAA------------- ... ).&lt;br />&lt;br />Agora, quando eu encontro uma linha que começa com teste_ eu:&lt;br />&lt;br />x) troco essa linha com a linha que esta na memória (a atual&lt;br />'teste_...' vai, outra volta).&lt;br />p) imprimo a linha que veio (AAAA---------- ...)&lt;br />g) pego a linha da memória (teste_...)&lt;br />p) imprimo a linha cachorrona&lt;br />&lt;br />Só que não fica como vc quer. Ai vc precisa fazer a sacanagem:&lt;br />&lt;br />&lt;span style="font-style:italic;">se uma linha NÃO tem o que eu quero, então eu a manipulo habilmente&lt;br />até que ela chegue ao que eu quero&lt;/span>&lt;br />&lt;br />Eu poderia ter usado varias tecnicas mas... uma vez com sed, podemos continuar nele.&lt;br />&lt;br />&lt;code>$ sed -rn '/(^[^-]+-+).*/{s//\1/;h};&lt;br />/^teste_/{s/.* ([^ ]+) +([^ ]+$)/\2 \1/;x;p;g;p}' arquivo.log&lt;/code>&lt;br />&lt;br />eu transformei a primera ER em (minha_ER).* -- ou seja, criei um &lt;span style="font-style:italic;">grupo&lt;/span> para o que me interessa. basta fazer:&lt;br />&lt;br />&lt;code>s/(minha_ER).*/\1/&lt;/code>&lt;br />&lt;br />para que toda a linha seja reduzida ao que a minha ER casa. em outras palavras, eu apaguei o resto da linha.&lt;br />&lt;br />na outra eu fui mais sacana pois eu tenho 2 grupos e troco toda a linha pelos grupos, na ordem inversa. coisa de quem toma muito café e não tem escrupulos.&lt;br />&lt;br />Vamos ver a versão &lt;span style="font-weight:bold;">AWK&lt;/span>?&lt;br />&lt;br />&lt;code>$ awk '/^[^-]+-+/{match($0,/^[^-]+-+/); x=substr($0,1,RLENGTH)}&lt;br />/^teste_/{print x,"\n"$5,$4}' arquivo.log&lt;br />AAAA-------------&lt;br />testetesteteste 38666&lt;br />BBBB-------------&lt;br />testetesteteste 26232207&lt;/code>&lt;br />&lt;br />x, nesse caso, armazena aquele pedaço da linha anterior, que eu descobri o que é via match. match procura uma expressão regular numa string, nesse caso em $0, e seta um valor na variavel RLENGTH, que é onde a expressão acaba. basta pegar essa parte da string e guardar na variavel x, que sera lida depois.&lt;br />&lt;br />Aqui fala um pouco dessas duas funções: &lt;a href="http://people.cs.uu.nl/piet/docs/nawk/nawk_92.html">http://people.cs.uu.nl/piet/docs/nawk/nawk_92.html&lt;/a>&lt;br />&lt;br />Eu poderia ter resolvido dessa forma também&lt;br />&lt;code>$ awk '/^[^-]+-+/{sub(/-[^-]+.*$/,"-");x=$0} &lt;br />/^teste_/{print x,"\n"$5,$4}' arquivo.log&lt;br />AAAA-------------&lt;br />testetesteteste 38666&lt;br />BBBB-------------&lt;br />testetesteteste 26232207&lt;/code>&lt;br />&lt;br />Entretanto aqui eu faço uma substituição grosseira do resto da linha que tem o AAAA------... por -, abusando do .* (e o fato dele ser guloso). Parece mais simples, mas está sujeito à falhas, embora não consigo pensar em nenhuma situação que seja possivem demonstrar.&lt;br />&lt;br />AWK &amp; SED são ferramentas sensacionais para esse tipo de problema ;-)&lt;/div>
&lt;h2>Comments&lt;/h2>
&lt;div class='comments'>
&lt;div class='comment'>
&lt;div class='author'>blpsilva&lt;/div>
&lt;div class='content'>
Impressive, to say the least :)&lt;BR/>&lt;BR/>Acho que chegou a hora de limpar a minha ferrugem e reler o Advanced Bash Scripting Guide.&lt;BR/>&lt;BR/>You produce some quite nice pearls inside the shell ;)&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Tiago Peczenyj&lt;/div>
&lt;div class='content'>
grep + awk + sed:&lt;BR/>&lt;BR/>$ grep -B 1 teste_ arquivo.log | \&lt;BR/>awk '/teste_/{print $5,$4; next} 1' | \&lt;BR/>sed -r '/^--$/d;s/(^[^-]+-+)[^-].*/\1/'&lt;BR/>&lt;BR/>AAAA-------------&lt;BR/>testetesteteste 38666&lt;BR/>BBBB-------------&lt;BR/>testetesteteste 26232207&lt;/div>
&lt;/div>
&lt;/div></description></item><item><title>Um corretor ortográfico em gawk</title><link>http://pacman.blog.br/blog/2008/04/13/um-corretor-ortogrfico-em-gawk/</link><pubDate>Sun, 13 Apr 2008 14:39:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2008/04/13/um-corretor-ortogrfico-em-gawk/</guid><description>&lt;div class='post'>
Ano passado eu publiquei &lt;a href="http://peczenyj.blogspot.com/2007/08/implementando-um-corretor-ortogrfico.html">uma pequena nota sobre um pequeno corretor ortográfico feito em Python&lt;/a>.&lt;br />&lt;br />No &lt;a href="http://norvig.com/spell-correct.html">artigo&lt;/a> do Peter Norwig, ele explica o principio estatístico do algoritmo. No final, ele mostra varias implementações do algoritmo (em D, Java, Ruby e até Erlang).&lt;br />&lt;br />Depois de muito pesquisar, decidi fazer uma versão em gawk. A primeira tinha 30 linhas e não funcionava muito bem, arrumando e testando cheguei a esta forma final com apenas 15 linhas.&lt;br />&lt;br />Eu chamo de linha um &lt;span style="font-style:italic;">statement&lt;/span> completo do awk. Perceba que nenhuma linha dessas possui o separador de statement &lt;span style="font-weight:bold;">;&lt;/span> (ponto-e-virgula), exceto quando estou utilizando o for no estilo C.&lt;br />&lt;br />&lt;pre>&lt;code># Usage: gawk -v word=something -f thisfile.awk [ big.txt [ big2.txt ... ]]&lt;br /># Gawk version with 15 lines -- 04/13/2008&lt;br /># Author: tiago (dot) peczenyj (at) gmail (dot) com &lt;br /># Based on : http://norvig.com/spell-correct.html&lt;br />function edits(w,max,candidates,list, i,j){&lt;br /> for(i=0;i&lt; max ;++i) ++list[substr(w,0,i) substr(w,i+2)] &lt;br /> for(i=0;i&lt; max-1;++i) ++list[substr(w,0,i) substr(w,i+2,1) substr(w,i+1,1) substr(w,i+3)] &lt;br /> for(i=0;i&lt; max ;++i) for(j in alpha) ++list[substr(w,0,i) alpha[j] substr(w,i+2)] &lt;br /> for(i=0;i&lt;= max ;++i) for(j in alpha) ++list[substr(w,0,i) alpha[j] substr(w,i+1)] &lt;br /> for(i in list) if(i in NWORDS) candidates[i] = NWORDS[i] }&lt;br />&lt;br />function correct(word ,candidates,i,list,max,temp){&lt;br /> edits(word,length(word),candidates,list)&lt;br /> if (!asort(candidates,temp)) for(i in list) edits(i,length(i),candidates)&lt;br /> return (max = asorti(candidates)) ? candidates[max] : word }&lt;br />&lt;br />BEGIN{ if (ARGC == 1) ARGV[ARGC++] = "big.txt" # http://norvig.com/big.txt&lt;br /> while(++i&lt;=length(x="abcdefghijklmnopqrstuvwxyz")) alpha[i]=substr(x,i,1)&lt;br /> IGNORECASE=RS="[^"x"]+" }&lt;br />&lt;br />{ ++NWORDS[tolower($1)] }&lt;br />&lt;br />END{ print (word in NWORDS) ? word : "correct("word")=> " correct(tolower(word)) }&lt;/code>&lt;/pre>&lt;br />&lt;br />Veja o script em funcionamento:&lt;br />&lt;pre>$ time gawk -v word=somethink -f spelling.awk&lt;br />correct(somethink)=> something&lt;br />&lt;br />real 0m4.862s&lt;br />user 0m4.702s&lt;br />sys 0m0.093s&lt;/pre>&lt;/div>
&lt;h2>Comments&lt;/h2>
&lt;div class='comments'>
&lt;div class='comment'>
&lt;div class='author'>Rael&lt;/div>
&lt;div class='content'>
Tiago, mais uma vez, parabéns!&lt;BR/>É muito divertido mexer com estas coisas, não?&lt;BR/>Ah, eu não esqueci de te mandar a versão otimizada em Java... eu só não achei seu email pra enviar! :P&lt;BR/>Me manda um email, e eu te dou reply!&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Tiago Albineli Motta&lt;/div>
&lt;div class='content'>
Corretor ortográfico, tatuagem... esse foi um final de semana divertido pra você heim! hahahha&lt;/div>
&lt;/div>
&lt;/div></description></item><item><title>Hackeando um Hello World com sed</title><link>http://pacman.blog.br/blog/2008/03/28/hackeando-um-hello-world-com-sed/</link><pubDate>Fri, 28 Mar 2008 17:55:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2008/03/28/hackeando-um-hello-world-com-sed/</guid><description>&lt;div class='post'>
Fantástico o que o sed pode fazer!&lt;br />&lt;br />&lt;pre>&lt;code>$ cat a.c&lt;br />main(){ &lt;br /> puts("hello world"); &lt;br />}&lt;br />$ gcc a.c&lt;br />$ ./a.out &lt;br />hello world&lt;br />$ sed -i 's/hello world/_ola mundo_/'./a.out &lt;br />$ ./a.out &lt;br />_ola mundo_&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Alterando Multiplos Arquivos (versão final?)</title><link>http://pacman.blog.br/blog/2008/02/22/alterando-multiplos-arquivos-verso/</link><pubDate>Fri, 22 Feb 2008 19:27:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2008/02/22/alterando-multiplos-arquivos-verso/</guid><description>&lt;div class='post'>
O site Dicas-L trouxe na ultima semana 2 formas de renomear multiplos arquivos (&lt;a href="http://www.dicas-l.com.br/dicas-l/20080219.php">aqui&lt;/a> e &lt;a href="http://www.dicas-l.com.br/dicas-l/20080221.php">aqui&lt;/a>)&lt;br />&lt;br />&lt;code>&lt;pre>#Forma 1&lt;br />for o in $(ls -1 *.txt); do&lt;br /> mv $o $(echo $o | awk -F. '{print $1".htm"}');&lt;br />done&lt;/pre>&lt;/code>&lt;br />&lt;br />&lt;code>&lt;pre>#Forma 2&lt;br />for i in `ls *.txt`; do&lt;br /> mv $i $(echo `basename $i .txt`.html)&lt;br />done&lt;/pre>&lt;/code>&lt;br />&lt;br />São ambas formas interessantes, porém ao meu ver consomem muito recursos da maquina, sem falar que são um tanto... feios... (nada contra - o que importa é que funcione)&lt;br />&lt;br />Vou utiliza-los como exemplo de como podemos tornar algo melhor e mais prático (se o tempo permitir).&lt;br />&lt;br />Vamos dividir as paradas:&lt;br />&lt;br />&lt;code>&lt;pre>altera() { mv $1 $(echo `basename $1 .txt`.html) ; }&lt;br />&lt;br />for i in `ls *.txt`; do&lt;br /> altera $i&lt;br />done&lt;/pre>&lt;/code>&lt;br />&lt;br />Agora vamos tomar um cuidado: arquivos com espaço no nome&lt;br />&lt;br />&lt;code>&lt;pre>altera() { mv "$1" $(echo `basename "$1" .txt`.html) ; }&lt;br />&lt;br />for i in `ls *.txt`; do&lt;br /> altera "${i}"&lt;br />done&lt;/pre>&lt;/code>&lt;br />&lt;br />Bom, o for pode iterar sobre uma lista de argumentos. As mascaras de nome de arquivo são expandidos pelo shell durante a execução, logo...&lt;br />&lt;br />&lt;code>&lt;pre>for i in *.txt ; do&lt;br /> altera "${i}"&lt;br />done&lt;/pre>&lt;/code>&lt;br />&lt;br />Agora, a rotina de alteração do nome do arquivo de destino é complicadissima, depende de um ou mais sub-processos. Isso poderia ser...&lt;br />&lt;br />&lt;code>&lt;pre>altera() { mv "$1" "${1%.txt}.html" ; }&lt;/pre>&lt;/code>&lt;br />&lt;br />Que, inserido no for...&lt;br />&lt;br />&lt;code>&lt;pre>for i in *.txt ; do&lt;br /> mv "${i}" "${i%.txt}.html"&lt;br />done&lt;/pre>&lt;/code>&lt;br />&lt;br />Interessante, certo? Nenhum sub-processo, exceto o inumeros mv que serão executados. Existem outras formas de fazer a mesma coisa&lt;br />&lt;br />&lt;code>&lt;pre>ls *.txt | awk -F. -v OFS=. '{ O=$0; $NF="html" ;printf "\"%s\" \"%s\"\n",O,$0 }' | xargs -n 2 mv&lt;br />&lt;br />ls *.txt | sed 's#^\(.\+\)\.[^.]\+$#"&amp;" "\1.html"#g' | xargs -n 2 mv &lt;/pre>&lt;/code>&lt;br />&lt;br />(rodem as linhas acima sem o mv do xargs para entende-las -- é metaprogramação)&lt;br />&lt;br />Agora... tudo isso é muito bonito mas... veja se o seu computador possui os comandos mmv ou rename (que facilitam Absurdamente a tarefa)&lt;br />&lt;br />&lt;code>&lt;pre>rename .txt .html *.txt&lt;br />&lt;br />mmv "*.txt" "#1.html"&lt;/pre>&lt;/code>&lt;br />&lt;br />Simples, não?&lt;br />&lt;br />Tudo depende do tempo que temos e das nossas necessidades. Mesmo que o rename/mmv sejam uteis, pode ser que a forma com awk / sed valha mais a pena pois o ls pode ser substituido por um find (ja pensou nisso?)&lt;/div>
&lt;h2>Comments&lt;/h2>
&lt;div class='comments'>
&lt;div class='comment'>
&lt;div class='author'>Leonardo Bernardes&lt;/div>
&lt;div class='content'>
Já conhecia o NF, depois de conhecê-lo queimei um pouco a cabeça tentando elaborar um método pra fazer essa passagem do 1 ao NF. Pensei em qualquer coisa semelhante ao while.. mas não veio nada.&lt;BR/>&lt;BR/>Na verdade, Tiago, sou um belo amador, brinco de fazer scripts como terapia.. terapia que eu realizava aos montes na época de mIRC.&lt;BR/>&lt;BR/>Por conta mesmo do meu amadorismo, não consegui entender seu exemplo de como queimar os registros intermediários. Mas não esquente com isso, se não há aquela variável mágica que eu usava no mIRC, é melhor que eu me contente com minhas limitações. Em todo caso, fico ligado nas suas dicas da seção shell.&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Tiago Peczenyj&lt;/div>
&lt;div class='content'>
Ola Leonardo.&lt;BR/>&lt;BR/>Infelizmente o gawk não tem o conceito de range. Quando vc utiliza o operador $X vc esta pegando o X-ésimo campo daquele registro. Vc tem uma variavel que é setada a cada registro que é NF, o numero de registros, que permite que vc leia o ultimo registro de forma simples&lt;BR/>&lt;BR/>print $1,$NF&lt;BR/>&lt;BR/>Agora... tem uma sacanagem que vc pode fazer: $0 é o registro inteiro, porém vc pode "queimar" alguns registros intermediarios&lt;BR/>&lt;BR/>no seu caso, se vc fizesse&lt;BR/>&lt;BR/>$3=$4=$5=$6=""&lt;BR/>print $0&lt;BR/>&lt;BR/>só sobraria o que vc quer.&lt;BR/>&lt;BR/>Uma forma, menos agressiva, seria tentar pegar um padrão via expressões regulares.&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Leonardo Bernardes&lt;/div>
&lt;div class='content'>
Tiago,&lt;BR/>&lt;BR/>Você parece o sujeito certo pra esclarecer um dúvida:&lt;BR/>&lt;BR/>Se eu quiser filtrar uma string do seguinte tipo&lt;BR/>&lt;BR/>7718 0.0 0.0 1756 476 ? Ss 17:59 0:00 /bin/sh -c pidgin&lt;BR/>&lt;BR/>Como AWK eu posso fazer através de algo como "awk '{print $1,$2,$10}'" &lt;BR/>&lt;BR/>Mas se eu quiser, por exemplo, filtrar o $1, o $2 e todos OS DEMAIS após o $7 sem saber o número total de termos, há alguma variável pra isso? Não sei se me fiz entender, mas essa dúvida me persegue desde que lembrei que quando eu brincava editando scripts no mIRC, uma simples $7- realizava essa função&lt;BR/>&lt;BR/>Desculpe o abuso, abraços&lt;/div>
&lt;/div>
&lt;/div></description></item><item><title>Twitter.sh versão 2.0</title><link>http://pacman.blog.br/blog/2008/01/30/twittersh-verso-20/</link><pubDate>Wed, 30 Jan 2008 09:02:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2008/01/30/twittersh-verso-20/</guid><description>&lt;div class='post'>
O Bruno me deu uma ótima sugestão: um simples &lt;span style="font-style:italic;">usage&lt;/span>.&lt;br />&lt;br />Entretanto ontem eu fiquei batendo cabeça com os inúmeros tac/tail's mas percebi q um sed resolvia a questão. Alias é possivel também passar uma lista de parâmetros também!&lt;br />&lt;pre>&lt;code>#!/bin/bash&lt;br />TWIURL=http://m.twitter.com # utilizando versão 'mobile' do twitter&lt;br />USAGEMSG="Usage: $(basename $0) &amp;lt;twitter-user&amp;gt; [user list...]"&lt;br />&lt;br />[ -z "$1" ] &amp;&amp; { echo "${USAGEMSG}" ; exit 1 ; }&lt;br />for i in "$@" ; do&lt;br /> echo "==============================="&lt;br /> links -dump "${TWIURL}/${i}" | sed -r '1,3d;/^\ +Older [0-9]+/,$d'&lt;br />done&lt;/code>&lt;/pre>&lt;br />Agora chega :)&lt;/div>
&lt;h2>Comments&lt;/h2>
&lt;div class='comments'>
&lt;div class='comment'>
&lt;div class='author'>Tiago Peczenyj&lt;/div>
&lt;div class='content'>
Oi Paulo,&lt;BR/>&lt;BR/>O Gabriel Stein me deu uma ótima ideia de como postar no twitter:&lt;BR/>&lt;BR/>http://gabrielstein.org/?p=181&lt;BR/>&lt;BR/>Estou pensando em fazer um script simples para ler e postar no twitter e isso pode evoluir para muita coisa :) Se quiser colaborar ou indicar como eu poderia divulgar mais, sinta-se à vontade.&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Paulo Diovani&lt;/div>
&lt;div class='content'>
Script interessante.&lt;BR/>Já pensou em fazer algum widget para desktop com ele? Ou quem sabe divulgar em alguma comunidade internacional para alguém fazê-lo.&lt;/div>
&lt;/div>
&lt;/div></description></item><item><title>AWK e Arrays Associativos</title><link>http://pacman.blog.br/blog/2007/10/31/awk-e-arrays-associativos/</link><pubDate>Wed, 31 Oct 2007 13:09:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/10/31/awk-e-arrays-associativos/</guid><description>&lt;div class='post'>
Um grande problema para quem trabalha com arrays associativos no AWK é&lt;br />com relação a ordem dos elementos quando esta fazendo uma iteração.&lt;br />&lt;br />Ex:&lt;br />&lt;pre>&lt;code>$ gawk 'BEGIN{ split("5 4 2 1 3",T) ; for(i in T) print T[i]}'&lt;br />1&lt;br />3&lt;br />5&lt;br />4&lt;br />2&lt;/pre>&lt;/code>&lt;br />&lt;br />Eu inseri, nessa ordem, 5, depois 4, depois 2... porém o acesso aos&lt;br />elementos de um array em um for do tipo&lt;br />&lt;pre>&lt;code>for( variavel in array)&lt;/pre>&lt;/code>&lt;br />é imprevisive / incontrolável.&lt;br />&lt;br />Agora vejamos isto:&lt;br />&lt;br />&lt;pre>&lt;code>$ WHINY_USERS=1 gawk 'BEGIN{ split("5 4 2 1 3",T) ; for(i in T) print T[i]}'&lt;br />5&lt;br />4&lt;br />2&lt;br />1&lt;br />3&lt;/pre>&lt;/code>&lt;br />&lt;br />WOW! Através da variavel de ambiente do unix WHINY_USERS agora eu consigo acessar os elementos na ordem em que eles foram inseridos no array!&lt;br />&lt;br />E para acessar os valores na ordem crescente:&lt;br />&lt;pre>&lt;code>$ WHINY_USERS=1 gawk 'BEGIN{ split("5 4 2 1 3",T)&lt;br /> asort(T) ; for(i in T) print T[i] }'&lt;br />1&lt;br />2&lt;br />3&lt;br />4&lt;br />5&lt;/pre>&lt;/code>&lt;br />&lt;br />A variavel de ambiente WHINY_USERS &lt;span style="font-weight:bold;">não&lt;/span> esta documentada no man, muito menos na documentação que consegui a respeito do gawk. Descobri esta dica no &lt;span style="font-style:italic;">comp.lang.awk&lt;/span> e, por incrivel que pareça, tive que vasculhar o codigo fonte do &lt;span style="font-style:italic;">gawk&lt;/span> (graças a deus podemos fazer isso) para entender melhor o que essa variavel poderia fazer.&lt;br />&lt;br />Enfim, fica a dica.&lt;/div></description></item><item><title>Convertendo Números</title><link>http://pacman.blog.br/blog/2007/10/01/convertendo-nmeros/</link><pubDate>Mon, 01 Oct 2007 19:29:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/10/01/convertendo-nmeros/</guid><description>&lt;div class='post'>
Um dos meus primeiros desafios na área de programação foi fazer um conversor de números decimais para romanos. Eu estava aprendendo Turbo Pascal e usava um potente 286 com 1MB de memória - sem HD.&lt;br />&lt;br />Fiz a maior sequencia de ifs da minha vida. Hoje estava relembrando e resolvi fazer uma versão SED.&lt;br />&lt;br />&lt;pre>&lt;code>/[0-9]*[5-9]...$/q&lt;br />s/1...$/M&amp;/;s/2...$/MM&amp;/;s/3...$/MMM&amp;/;s/4...$/MMMM&amp;/&lt;br />s/6..$/DC&amp;/;s/7..$/DCC&amp;/;s/8..$/DCCC&amp;/;s/9..$/CM&amp;/&lt;br />s/1..$/C&amp;/;s/2..$/CC&amp;/;s/3..$/CCC&amp;/;s/4..$/CD&amp;/;s/5..$/D&amp;/&lt;br />s/6.$/LX&amp;/;s/7.$/LXX&amp;/;s/8.$/LXXX&amp;/;s/9.$/XC&amp;/&lt;br />s/1.$/X&amp;/;s/2.$/XX&amp;/;s/3.$/XXX&amp;/;s/4.$/XL&amp;/;s/5.$/L&amp;/&lt;br />s/1$/I/;s/2$/II/;s/3$/III/;s/4$/IV/;s/5$/V/&lt;br />s/6$/VI/;s/7$/VII/;s/8$/VIII/;s/9$/IX/&lt;br />s/[0-9]//g&lt;/pre>&lt;/code>&lt;br />&lt;br />Tendo um número por linha ja basta. &lt;br />&lt;br />&lt;pre>$ echo '3999' | sed -f other.sed&lt;br />MMMCMXCIX&lt;/pre>&lt;br />&lt;br />O sed é realmente fantástico! Pena que acima de 5 mil tem que colocar &lt;a href="http://en.wikipedia.org/wiki/Roman_numerals">uma barra em cima dos números&lt;/a>.&lt;/div>
&lt;h2>Comments&lt;/h2>
&lt;div class='comments'>
&lt;div class='comment'>
&lt;div class='author'>voyeg3r&lt;/div>
&lt;div class='content'>
Também sou super fã do SED, estou no momento criando um script para converter um wiki do pbwiki para moinmoin, são mais de 300 páginas e adição manual seria um trabalho digno para um usuário windows :)&lt;/div>
&lt;/div>
&lt;/div></description></item><item><title>Metaprogramação com awk e sed</title><link>http://pacman.blog.br/blog/2007/08/28/metaprogramao/</link><pubDate>Tue, 28 Aug 2007 15:17:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/08/28/metaprogramao/</guid><description>&lt;div class='post'>
Criar um programa que cria programas é simples nas linguagens interpretadas.&lt;br />&lt;br />Criamos o programa em uma string e executamos via &lt;span style="font-weight:bold;">eval()&lt;/span> ou então gravamos em arquivo e executamos novamente.&lt;br />&lt;br />Me deparei com o seguinte problema: inverter as palavras de uma frase ou arquivo &lt;span style="font-weight:bold;">mantendo&lt;/span> a ordem em que aparecem.&lt;br />&lt;br />É claro que eu pensei em usar o rev, mas ele inverte a linha como um todo. Depois de fazer um laço for muito feio em awk, fiquei pensando em como resolver de forma mais legível.&lt;br />&lt;br />Tive esta ideia: vou fazer uma lista de palavras, inverte-las com o rev e, para cada palavra, vou substitui-la pela palavra invertida. Beleza, o &lt;span style="font-weight:bold;">sed &lt;/span>faz isso com um pé nas costas.&lt;br />&lt;br />Eu tenho um arquivo (poderia ser um &lt;a href="http://twiki.softwarelivre.org/bin/view/TWikiBar/TWikiBarPapo011#Named_Pipes">named pipe&lt;/a>) chamado 'direito' que contem uma lista de palavras sem repetição, com uma palavra por linha. Outro arquivo, com o mesmo conteudo mas revertido via 'rev'.&lt;br />&lt;br />Uso o paste para colocar os arquivo lado a lado e uso o awk para gerar comandos como este:&lt;pre>s/\bpalavra\b/palavra_revertida/g;&lt;/pre>&lt;br />&lt;br />Usei o awk pq a sintaxe fica mais clara, o sed ficou muito poluído. Perceba que eu uso o recurso de &lt;span style="font-weight:bold;">borda&lt;/span> das expressões regulares. Isso me garante que vou trocar uma palavra inteira, e não um pedaço da string.&lt;br /> &lt;br />Agora vem o pulo do gato: mando estes comandos via &lt;span style="font-style:italic;">stdin &lt;/span>para o sed, fazendo uso de um pipe. eu informo para o sed que os comandos virão pela stdin passando a opção -f -&lt;br />&lt;br />Vejam o resultado abaixo, espero que seja útil para alguem :)&lt;br />&lt;br />&lt;pre>&lt;code>$ cat stuff&lt;br />Nosso fórum principal.&lt;br />&lt;br />Problemas com hardware em geral,&lt;br />&lt;br />temperaturas, comparação de desempenho,&lt;br />&lt;br />compatibilidades de componentes, etc.&lt;br />&lt;br />$ LC_ALL=pt_BR grep -oE '\w+' stuff | sort -u | tee direito | rev > reverso&lt;br />&lt;br />$ paste direito reverso | awk '{&lt;br /> printf "s/\\b%s\\b/%s/g;\n",$1,$2 # facil, não?&lt;br /> }' | sed -f - stuff&lt;br />ossoN muróf lapicnirp.&lt;br />&lt;br />samelborP moc erawdrah me lareg,&lt;br />&lt;br />sarutarepmet, oãçarapmoc ed ohnepmesed,&lt;br />&lt;br />sedadilibitapmoc ed setnenopmoc, cte.&lt;/code>&lt;/pre>&lt;br />Como o arquivo possui acentos, precisei setar a variavel &lt;span style="font-weight:bold;">LC_ALL&lt;/span> para &lt;span style="font-weight:bold;">pt_BR&lt;/span>, caso contrario a expressão regular &lt;span style="font-weight:bold;">\w+&lt;/span> não iria casar com todas as palavras.&lt;br />&lt;br />Ps: Julio, que tal chamar isso de "Inversor do Tiago"?&lt;/div>
&lt;h2>Comments&lt;/h2>
&lt;div class='comments'>
&lt;div class='comment'>
&lt;div class='author'>Tiago Peczenyj&lt;/div>
&lt;div class='content'>
O que acontece é o seguinte:&lt;BR/>&lt;BR/>cada vez que vc invoca o comando rev, vc perde tempo com a inicialização do programa e seu término. Eu utilizei o rev apenas uma vez, mas vc executa a cada palavra.&lt;BR/>&lt;BR/>É a mesma diferença de&lt;BR/>&lt;BR/>for i in *.txt ; do rm $i ; done&lt;BR/>&lt;BR/>e rm *.txt&lt;BR/>&lt;BR/>A segunda forma recebe ja todos os parâmetros e só tem o trabalho de iterar internamente sobre esta lista. A primeira forma cria um custoso laço por conta do detalhe que eu ja lhe falei.&lt;BR/>&lt;BR/>Shel é sensacional, porém não pode ser pensado como uma linguagem script sempre, ele é uma forma de interação do usuario com o sistema ;-)&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Leandro Santiago&lt;/div>
&lt;div class='content'>
Mas, se você transformar esse for acima numa função, tipo&lt;BR/>InverteFrase()&lt;BR/>{&lt;BR/> local IFS=' ' # tab e espaço&lt;BR/> string=($@)&lt;BR/> for (( i=0; i&lt;=${#string[@]}; i+=1 ))&lt;BR/> {&lt;BR/> echo ${string[$i]} | rev | tr "\n" ' '&lt;BR/> }&lt;BR/>}&lt;BR/>&lt;BR/>Pode utilizar para fazer num arquivo, simplesmente tomando cada linha como uma string independente:&lt;BR/>&lt;BR/>while read LINHA&lt;BR/>do&lt;BR/> InverteFrase $LINHA&lt;BR/> echo ## esse daqui é para quebrar a linha, no final de cada frase&lt;BR/>done &lt; &lt;(cat arquivo_de_texto)&lt;BR/>&lt;BR/>Nossa, esse meu aí demorou 18 segundos num arquivo de textos simples, mas em compensação não precisa escrever em disco. Contra o seu método, que no mesmo arquivo demorou 0.12 segundo... hauhaau&lt;BR/>&lt;BR/>Flw, e foi mal invadir assim o seu blog ;-)&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Leandro&lt;/div>
&lt;div class='content'>
Poderia também utilizar vetores, num forzão bem cabuloso.&lt;BR/>Exemplo:&lt;BR/>$ read string&lt;BR/>o rato roeu a roupa do rei de roma&lt;BR/>$ string=($string)&lt;BR/>$ for (( i=0; i&lt;=${#string[@]}; i+=1 ))&lt;BR/>> {&lt;BR/>> echo ${string[$i]} | rev | tr "\n" ' '&lt;BR/>> }&lt;BR/>o otar ueor a apuor od ier ed amor&lt;BR/>&lt;BR/>Mas só funciona com uma só string... rsrs. Só é muito lento, pois o rev, que troca palavra por palavra, é executado muuitas vezes, quebrando a linha, o que me obriga a utilizar um tr para substituir as quebras por espaço... Fica muito lento... (mas funciona para uma string ;-))&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Tiago Peczenyj&lt;/div>
&lt;div class='content'>
Ola NetWalker,&lt;BR/>&lt;BR/>Pois bem, o sed pode parecer dispendioso, porém em alguns casos a perda de desempenho é imperceptível. Sem falar que a sintaxe dele é mais clara (99% dos casos eu uso a opção de busca e substituição).&lt;BR/>&lt;BR/>Mas perceba que o sed pode ser usado de forma mais otimizada, como o caso de imprimir apenas a linha 105 de um grande arquivo:&lt;BR/>&lt;BR/>sed -n '105q;d' arquivo&lt;BR/>&lt;BR/>sed + awk são uma dupla muito interessante ;-)&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>NetWalker&lt;/div>
&lt;div class='content'>
Cá denovo. :)&lt;BR/>Depois de achar um exemplo teu de inversor em sed pela net (assustador lol), lhe pergunto: que faz/fez tanto com sed?? :D&lt;BR/>Outra questão q intriga fora o uso real desse inversor (http://www.alltooflat.com/geeky/elgoog/ ?? weird heheh); é se já fez alguma avaliação sobre a performance do sed em relação ao awk, ou mesmo tarefas q possam ser substituídas por grep, cut, expansões e afins.&lt;BR/>Pois em alguns casos sed me pareceu meio dispendioso. Porém não conheço sed a fundo para saber sobre o quanto os comandos estavam otimizados.&lt;BR/>E adiantando, muito boa essa indicação do "On The Lot". Não conhecia. :) Ótimos posts como sempre.&lt;BR/>Então é isso.&lt;BR/>Farewell.&lt;BR/>&lt;BR/>NetWalker&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>match&lt;/div>
&lt;div class='content'>
bem legaw, olha, estou usando o tput e para me familiarizar com ele resolvi fazer algo pratico brincando com ele e fazendo a "Screen Matrix" em shel, consiste em usar colunas fixas no tput com linhas aleatorias pra gerar akela chuva verde de caracters do Matrix Movie, saiu meio bagunçado e n tive tempo ainda de por uma ordem, talvez vc esteja interessando em ajudar o codigo estah em: http://crimeboy.110mb.com/neo.sh&lt;BR/>[]z&lt;/div>
&lt;/div>
&lt;/div></description></item><item><title>Extended Globbing</title><link>http://pacman.blog.br/blog/2007/08/28/extended-globbing/</link><pubDate>Tue, 28 Aug 2007 15:15:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/08/28/extended-globbing/</guid><description>&lt;div class='post'>
Não sei se é conhecimento de todos mas o Bash possui, alem do globbing normal (a expansão * ? e [a-z] de nomes de arquivos e diretórios), um globbing extendido.&lt;br />&lt;br />Acho que, em alguns casos, podera ser BEM util, eliminando um pipe para um grep por exemplo.&lt;br />&lt;br />São eles (direto do man)&lt;br />&lt;pre>?(pattern-list)&lt;br /> Matches zero or one occurrence of the given patterns&lt;br />*(pattern-list)&lt;br /> Matches zero or more occurrences of the given patterns&lt;br />+(pattern-list)&lt;br /> Matches one or more occurrences of the given patterns&lt;br />@(pattern-list)&lt;br /> Matches exactly one of the given patterns&lt;br />!(pattern-list)&lt;br /> Matches anything except one of the given patterns&lt;/pre>&lt;br />Para poder utiliza-lo precisa executar o shopt conforme o exemplo abaixo&lt;br />&lt;br />&lt;pre>&lt;code>$ shopt -s extglob&lt;br />&lt;br />$ ls&lt;br />file filename filenamename fileutils&lt;br />&lt;br />$ ls file?(name) # padrão pode aparecer 0 a 1 vezes&lt;br /> &lt;br />file filename&lt;br />&lt;br />$ ls file*(name) # padrão pode aparecer 0 a N vezes&lt;br />file filename filenamename&lt;br />&lt;br />$ ls file+(name) # padrão pode aparecer 1 a N vezes&lt;br />filename filenamename&lt;br />&lt;br />$ ls file@(name) # padrão deve aparecer 1 unica vez&lt;br />filename&lt;br />&lt;br />$ ls file!(name) # divertido esse! padrão NÃO deve aparecer&lt;br />file filenamename fileutils&lt;br />&lt;br />$ ls file+(name|utils) # cada padrão pode aparecer 1 a N vezes&lt;br />filename filenamename fileutils&lt;br />&lt;br />$ ls file@(name|utils) # "lembra" um file{name,utils} ;-)&lt;br />filename fileutils&lt;/code>&lt;/pre>&lt;/div>
&lt;h2>Comments&lt;/h2>
&lt;div class='comments'>
&lt;div class='comment'>
&lt;div class='author'>Tiago Peczenyj&lt;/div>
&lt;div class='content'>
Para um administrador é interessante saber as opções huponexit e restricted_shell -- e depois dizem que o shell é complicado.&lt;BR/>&lt;BR/>Po é cada coisa util que tem :)&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>NetWalker&lt;/div>
&lt;div class='content'>
Hail again Peczenyj. :)&lt;BR/>Esse recurso extended globbing realmente é uma mão-na-roda. Isso sem falar em outros built-in do shell acessíveis pelo shopt. Lembrei de um comum q alguns odeiam, e tem quem goste: o cdspell; e mesmo o cmdhist.&lt;BR/>No mais vale lembrar, pra quem visita, o óbvio desses globbings, q é um globbing poder "englobbar" outro. :P&lt;BR/>Assim sendo: ls file!(+(name))&lt;BR/>Eliminando qualquer ocorrência de name.&lt;BR/>Até +.&lt;BR/>&lt;BR/>NetWalker&lt;/div>
&lt;/div>
&lt;/div></description></item><item><title>Google Wars</title><link>http://pacman.blog.br/blog/2007/08/07/google-wars/</link><pubDate>Tue, 07 Aug 2007 18:43:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/08/07/google-wars/</guid><description>&lt;div class='post'>
Inutilidade Pública: veja o que/quem possui mais resultados no google?&lt;br />&lt;br />&lt;pre>&lt;code>./GoogleWars.sh superman batman&lt;br />&lt;span style="color:red;">batman 48500000&lt;/span>&lt;br />superman 33700000&lt;br />&lt;br />./GoogleWars.sh gremio inter&lt;br />&lt;span style="color:red;">inter 213000000&lt;/span>&lt;br />gremio 5560000&lt;br />&lt;br />./GoogleWars.sh hp ibm&lt;br />&lt;span style="color:red;">hp 379000000&lt;/span>&lt;br />ibm 147000000&lt;br />&lt;br />./GoogleWars.sh cobol java fortran perl ruby lisp haskell&lt;br />&lt;span style="color:red;">java 272000000&lt;/span>&lt;br />perl 103000000&lt;br />ruby 101000000&lt;br />lisp 21400000&lt;br />fortran 17400000&lt;br />haskell 15400000&lt;br />cobol 10900000&lt;/code>&lt;/pre>&lt;br />O script é simples, abusando um pouco do SED e do AWK, com um toque de SORT ;-)&lt;br />&lt;br />&lt;pre>&lt;code>#!/bin/bash&lt;br />COR=`echo -ne '\e[31;1m'`&lt;br />END=`echo -ne '\e[m'`&lt;br />CORSED="1s/.*/${COR}&amp;${END}/"&lt;br />GOOGLE='http://www.google.com/search'&lt;br />&lt;br />[[ $2 ]] || { echo "usage: $0 item item2 [ ... item n]" ; exit 0 ; }&lt;br />&lt;br />SEDCMD='/did not match any documents/{s/.*/0/g;p;q}&lt;br /> /Results/{s/.* about[ ]\+\([0-9,.]\+\).*/\1\n/;p;q}'&lt;br />AWKCMD='{ result[$1]=$2 ; x = length($1) ; if(x > max) max=x }&lt;br /> END{ for(i in result) printf "%-"max"s\t%s\n",i,result[i]}'&lt;br />&lt;br />for i in "$@" ; do echo -ne "${i}\t" &lt;br /> lynx -dump "${GOOGLE}?q=${i}" | tr -d '\n.,' | sed -n "${SEDCMD}" &lt;br />done | awk -F '\t' "${AWKCMD}" | sort -nr -t $'\t' -k 2 | sed "${CORSED}"&lt;/pre>&lt;/code>&lt;br />&lt;br />Quem quiser melhora-lo, sinta-se à vontade :)&lt;br />&lt;br />Edit: ja lancei uma versão .02 com umas correções cosméticas &lt;a href="http://pastebin.com/f2459820a">aqui&lt;/a> -- não resisti...&lt;/div></description></item><item><title>Considerações de Segurança</title><link>http://pacman.blog.br/blog/2007/08/06/consideraes-de-segurana/</link><pubDate>Mon, 06 Aug 2007 14:21:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/08/06/consideraes-de-segurana/</guid><description>&lt;div class='post'>
Me irrita profundamente usar um script que pressupõe certas definições no meu ambiente sem aviso prévio. O caso mais comum é, em algum *nix, acreditar que o diretório corrente faz parte do PATH -- contrariando uma regra básica de segurança, inclusive.&lt;br />&lt;br />Não é dificil fazer ./&lt;span style="font-style:italic;">programa&lt;/span> (na verdade com o tempo isso vira padrão até). Fica uma dica importante: nunca façam suposições a respeito do ambiente, variaveis, estruturas de diretórios sem documentar ou fazer os testes necessários (pelo menos quando for fora de algum &lt;span style="font-style:italic;">padrão&lt;/span>).&lt;/div></description></item><item><title>Caçadores da Classe Perdida</title><link>http://pacman.blog.br/blog/2007/08/03/caadores-da-classe-perdida/</link><pubDate>Fri, 03 Aug 2007 16:20:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/08/03/caadores-da-classe-perdida/</guid><description>&lt;div class='post'>
Eu já tinha feito algo parecido mas este &lt;a href="http://www.claudius.com.br/blog/claudio/2007/07/29/Como-encontrar-uma-classe">post&lt;/a> do Claudio Miranda reavivou a minha memória.&lt;br />&lt;br />&lt;pre>&lt;code>#!/bin/bash&lt;br />[[ $2 ]] || { echo "Uso: ${0} diretorio classe" ; exit 1 ; }&lt;br />find "${1}" -name \*.jar -print | xargs -n 1 unzip -l 2>&amp;- | awk -v class="${2}" '&lt;br /> BEGIN { IGNORECASE=1 }&lt;br /> /^Archive/ { file="\nArquivo:\n\t"$NF": \nClasses:\n\t" }&lt;br /> /class$/ &amp;&amp; $NF ~ class { print file,$NF ; file="\t"; total++ }&lt;br /> END { print "\nTotal",total + 0,"classes encontradas!" }'&lt;/code>&lt;/pre>&lt;br />&lt;br />Informando como parâmetros um diretório de partida e um fragmento do nome da classe, o find localizará todos os arquivos com extensão jar e vai mandar pro nosso amigo xargs. Este envia um a um para o unzip que lista (-l) o conteúdo de cada arquivo. Eu poderia procurar a classe que eu quero com o grep, mas o awk foi a escolha para formatar melhor a saída de dados.&lt;br />&lt;br />Perceba que a variavel IGNORECASE tem valor diferente de 0, assim eu posso procurar por um trecho do tipo xml ou XML. Eu preciso saber o nome do arquivo 'corrente' e isso é informado pela linha que começa com 'Archive'. Quando eu encontro uma linha que termina com 'class' e o ultimo campo ( $NF ) 'casa' com o fragmento de nome (alias pode ser uma expressão regular!) eu imprimo esta linha.&lt;br />&lt;br />Eu fiz uma sacanagem pra saída de dados ficar 'bonitinha', que é imprimir o 'cabeçalho' apenas uma vez, depois eu troco por tab (\t) -- e no final eu mostro um sumário com o número de referências encontradas.&lt;br />&lt;br />Este script pode ser modificado para outros propósitos. Note que eu procuro tanto no nome da classe quando no nome dos pacotes (diretórios), assim xml poderia casar com XMLHelper.class ou /java/xml/foobar.jar -- mas basta ser criativo para resolver isso!&lt;/div>
&lt;h2>Comments&lt;/h2>
&lt;div class='comments'>
&lt;div class='comment'>
&lt;div class='author'>Tiago Peczenyj&lt;/div>
&lt;div class='content'>
AWK é extremamente versátil!&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Claudio Miranda&lt;/div>
&lt;div class='content'>
Olá Tiago, obrigado pela dica-dica e manter a formatação de saída. Vou aprender um pouco mais de AWK.&lt;/div>
&lt;/div>
&lt;/div></description></item><item><title>Usando o curl com Endereços IPv6</title><link>http://pacman.blog.br/blog/2007/08/02/usando-o-curl-com-endereos-ipv6/</link><pubDate>Thu, 02 Aug 2007 13:28:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/08/02/usando-o-curl-com-endereos-ipv6/</guid><description>&lt;div class='post'>
Hoje em dia usar endereçamento &lt;a href="http://pt.wikipedia.org/wiki/IPv6">IPv6&lt;/a> parece um pouco exótico, porém aos poucos ele começa a aparecer em algumas redes internas e logo será a unica saída quando todos os 32 bits do IPv4 estiverem em uso, previsto para 2012.&lt;br /> &lt;br />Diga adeus ao "206.45.32.234" - longa vida ao "2001:bce4:5641:3412:341:45ae:fe32:65". Perceba como agora utilizamos a representação hexadecimal e cada quarteto é separado por um ':' -- o que torna mais fácil a sua memorização (e viva o DNS). Um bom artigo introdutório pode ser lido &lt;a href="http://www.guiadohardware.net/artigos/entendendo-ipv6/">aqui&lt;/a>.&lt;br />&lt;br />Pois bem, imagine agora que precisamos acessar uma pagina em um servidor (por enquanto interno) através de um endereço IPv6. A url ficaria assim, por exemplo:&lt;br />&lt;br />&lt;pre>&lt;code>http://[2001:bce4:5641:3412:341:45ae:fe32:65]:8000/index.php&lt;/code>&lt;/pre>&lt;br />&lt;br />Como o caracter ':' é usado em uma url para separar o servidor da porta (é claro que isso é omitido na maioria dos casos, quando usamos a porta 80), e tiveram que proteger o ip entre [colchetes]. Um browser como o Firefox consegue entender esta url facilmente, entretanto não tive a mesma sorte ao usar os browsers modo texto mais comuns - lynx e o curl. &lt;br />&lt;br />Não subestime a importância destes browsers! Muitas vezes nos encontramos em um sistema com poucos recursos ou precisamos efetuar certas ações via algum script e eles caem como uma luva -- principalmente o curl, que simplesmente transfere informações de/para um servidor web, fazendo GET, POST, HEAD, upload de arquivos, etc. &lt;br />&lt;br />No man do curl descobri que o mesmo depende da libcurl ser capaz de resolver endereços ipv6 - inclusive posso forçar a usar apenas ipv6 com a opção -6.&lt;br />&lt;br />Entretanto o curl tem outra interpretação dos colchetes em uma url -- elas são um recurso de sequência para multiplos downloads (da mesma forma como o bash faz, porém é interno ao curl), como nesse exemplo:&lt;br />&lt;br />&lt;pre>&lt;code>curl 'http://www.any.org/archive[1996-1999]/volume[1-4]part{a,b,c,index}.html'&lt;/code>&lt;/pre>&lt;br />&lt;br />Para desabilitar este "URL globbing parser" basta usar a opção -g, o que nos leva a solução completa:&lt;br />&lt;br />&lt;pre>&lt;code>curl -6g 'http://[2001:bce4:5641:3412:341:45ae:fe32:65]:8000/index.php'&lt;/code>&lt;/pre>&lt;br />&lt;br />Caso não queria desabilitar o globbing, basta 'escapar' os colchetes usando a contra-barra antes. O curl é um programa extremamente versátil, um verdadeiro canivete suíço na linha de comando, vale a pena estuda-lo em algum tempinho livre.&lt;/div></description></item><item><title>Resolvendo Problemas Comuns 7 - open failed: |</title><link>http://pacman.blog.br/blog/2007/07/26/resolvendo-problemas-comuns-7-open/</link><pubDate>Thu, 26 Jul 2007 14:03:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/07/26/resolvendo-problemas-comuns-7-open/</guid><description>&lt;div class='post'>
Imagine um arquivo com algumas linhas duplicadas:&lt;br />&lt;pre>&lt;code>$ cat arquivo&lt;br />permission denied&lt;br />bad interpreter&lt;br />missing separator&lt;br />set correct localle&lt;br />parameter list too long&lt;br />unary operator expected&lt;br />parameter list too long&lt;br />bad interpreter&lt;/code>&lt;/pre>&lt;br />&lt;br />Obter as linhas distintas pode ser feito com a ajuda do sort + uniq&lt;br />&lt;br />&lt;pre>&lt;code>$ cat arquivo | sort | uniq&lt;br />bad interpreter&lt;br />missing separator&lt;br />parameter list too long&lt;br />permission denied&lt;br />set correct localle&lt;br />unary operator expected&lt;/code>&lt;/pre>&lt;br />&lt;br /> - Puxa! Que ótima combinação! Vamos guarda-la?&lt;br />&lt;br />Bom, podemos querer guardar este e outros comandos em uma variável de ambiente também, afinal, deve funcionar sem maiores problemas, certo?&lt;br />&lt;pre>&lt;code>$ CMD="sort | uniq"&lt;br />$ cat arquivo | $CMD&lt;br />&lt;span style="font-weight:bold;">sort: open failed: |: No such file or directory&lt;/span>&lt;/code>&lt;/pre>&lt;br />&lt;br /> - OPA! Eu sabia, maldito shell, encrenca com tudo!&lt;br /> &lt;br />Tsc... isso acontece porque o pipe | não foi informado como um 'pipe' e sim como a string "|" -- e o sort não conseguiu abrir o arquivo "|".&lt;br />Este tipo de problema pode ser resolvido pelo eval -- ele interpreta novamente as strings na linha de comando.&lt;br />&lt;pre>&lt;code>$ eval "cat arquivo | $CMD"&lt;br />bad interpreter&lt;br />missing separator&lt;br />parameter list too long&lt;br />permission denied&lt;br />set correct localle&lt;br />unary operator expected&lt;/code>&lt;/pre>&lt;br />&lt;br /> - Ah, agora funciona. Mas esse eval ai ficou feio...&lt;br />&lt;br />Então vamos criar um alias para o comando!&lt;br />&lt;pre>&lt;code>$ alias cmd="sort | uniq"&lt;br />$ cat arquivo | cmd&lt;br />bad interpreter&lt;br />missing separator&lt;br />parameter list too long&lt;br />permission denied&lt;br />set correct localle&lt;br />unary operator expected&lt;/code>&lt;/pre>&lt;br />&lt;br />Perceba que o comportamento do alias é diferente de uma variavel de ambiente. Devemos ficar atento à correta interpretação da nossa linha de comando pelo shell corrente, senão vamos ter resultados nem sempre amigáveis.&lt;br />&lt;br />Ah, sim, o cat nesse exemplo é completamente supérfluo, poderia ser assim: 'sort arquivo | uniq' &lt;br />&lt;br /> - E o uniq precisa do sort ? &lt;br /> &lt;br />Sim... sem o sort ele fatalmente vai se perder, e é muito mais facil eliminar linhas repetidas que estejam em sequencia do que aleatórias. É bom dar uma lida no man destes comandos pois possuem opções muito poderosas!&lt;/div>
&lt;h2>Comments&lt;/h2>
&lt;div class='comments'>
&lt;div class='comment'>
&lt;div class='author'>Tiago Peczenyj&lt;/div>
&lt;div class='content'>
Claro, sort + uniq é um prato cheio! &lt;BR/>&lt;BR/>Uma coisa interessante é nessa dupla é, por exemplo, imprimir apenas as linhas repetidas ou não repetidas de um texto (opções -u ou -d) e, quando a entrada vem ordenada, o resultado é extremamente confiável.&lt;BR/>&lt;BR/>Entretanto não lembro se não existe algum furo no sort -u apenas, vou pesquisar.&lt;BR/>&lt;BR/>Abração!&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Alexsander&lt;/div>
&lt;div class='content'>
Olá! muito boas as dicas q tens disponibilizado!&lt;BR/>só uma sugestão:&lt;BR/>"sort -u" também remove duplicidades.&lt;BR/>abraços&lt;BR/>t+&lt;/div>
&lt;/div>
&lt;/div></description></item><item><title>Resolvendo Problemas Comuns 6 - unary operator expected</title><link>http://pacman.blog.br/blog/2007/07/26/resolvendo-problemas-comuns-6-unary/</link><pubDate>Thu, 26 Jul 2007 13:07:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/07/26/resolvendo-problemas-comuns-6-unary/</guid><description>&lt;div class='post'>
Uma desatenção, muito comum quando trabalhamos com variáveis de ambiente no shell é que, quando elas não foram setadas ainda, o shell expande elas para... nada.&lt;br />&lt;br />&lt;pre>&lt;code>$ [ $XALALA == "oi" ] &amp;&amp; echo 'ok' || echo 'nok'&lt;br />-bash: [: ==: unary operator expected&lt;br />nok&lt;/code>&lt;/pre>&lt;br />&lt;br />Nesse caso o (resultado do) teste da variável até pode fazer sentido, porém troque o == por um != e veja o resultado. A solução é proteger a variável com aspas!&lt;br />&lt;br />&lt;pre>&lt;code>$ [ "$XALALA" != "oi" ] &amp;&amp; echo 'ok' || echo 'nok'&lt;br />ok&lt;/code>&lt;/pre>&lt;br />&lt;br />Simples e rápido!&lt;/div>
&lt;h2>Comments&lt;/h2>
&lt;div class='comments'>
&lt;div class='comment'>
&lt;div class='author'>Tiago Peczenyj&lt;/div>
&lt;div class='content'>
Bah, não tinha reparado nisso.&lt;BR/>&lt;BR/>E faz sentido, afinal [[ é built-in e [ é, geralmente, um apelido para o comando /bin/test&lt;BR/>&lt;BR/>valeu!&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Cláudio&lt;/div>
&lt;div class='content'>
Outra solução: usar [[ ]] ao invés de [ ].&lt;/div>
&lt;/div>
&lt;/div></description></item><item><title>Resolvendo Problemas Comuns 5 - The parameter list is too long</title><link>http://pacman.blog.br/blog/2007/07/26/resolvendo-problemas-comuns-5-parameter/</link><pubDate>Thu, 26 Jul 2007 12:50:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/07/26/resolvendo-problemas-comuns-5-parameter/</guid><description>&lt;div class='post'>
Essa é raro, mas acontece&lt;br />&lt;br />&lt;code>&lt;pre>$ cd /meu/diretorio&lt;br />$ rm *.dll&lt;br />Error: The parameter list is too long&lt;/pre>&lt;/code>&lt;br />&lt;br /> - O que? Eu não posso apagar todos os meus 3459834574935734957 arquivos?&lt;br />&lt;br />Bom, primeiro vamos analisar o que aconteceu: a linha de comando 'rm *.dll' é expandida pelo shell corrente a 'rm arquivo1.dll arquivo2.dll ... arquivoN.dll' e, nesse caso, esta lista de parâmetros foi demais pro probrezinho do rm. &lt;br />&lt;br />Com o &lt;span style="font-weight:bold;">xargs&lt;/span> é facil de resolver!&lt;br />&lt;code>&lt;pre>$ find /meu/diretorio -name '*.dll' -print | xargs rm&lt;/pre>&lt;/code>&lt;br />&lt;br />O que ele faz? o xargs recebe pela &lt;span style="font-style:italic;">stdin&lt;/span> toda uma lista de parâmetros que será entregue ao programa rm. Se esta lista extender o limite do sistema, então o xargs, inteligentemente, irá executar o rm uma vez, com a lista que for possível e, depois, executar de novo, até que todos os parâmetros sejam lidos. Aliás o xargs possui muitas opções interessantes, vale a pena dar uma estudada nele.&lt;br />&lt;br />E assim todas as dll's são apagadas -- em definitivo, pois com rm 'tr00' não tem undelete ;-)&lt;/div>
&lt;h2>Comments&lt;/h2>
&lt;div class='comments'>
&lt;div class='comment'>
&lt;div class='author'>Tiago Peczenyj&lt;/div>
&lt;div class='content'>
Ah sim, quem limita/expande os coringas é o shell. Acho que escrevi uma frase ambígua -- valeu!&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>eljunior&lt;/div>
&lt;div class='content'>
na verdade a lista de parâmetros não foi demais para o `rm', quem limita isso é o próprio shell (tanto é que, num caso desses, nem um ls * funciona...). também não funcionaria somente `xargs rm', se fosse limitação do `rm'; seria necessário limitar a quantidade de parâmetros com a opção -n pro `xargs'. ;-)&lt;BR/>&lt;BR/>nas máquinas que usei, o limite do bash geralmente fora 32768 parâmetros...&lt;BR/>&lt;BR/>falou!&lt;/div>
&lt;/div>
&lt;/div></description></item><item><title>Resolvendo Problemas Comuns 4 - Corrigindo o localle</title><link>http://pacman.blog.br/blog/2007/07/26/resolvendo-problemas-comuns-4/</link><pubDate>Thu, 26 Jul 2007 12:20:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/07/26/resolvendo-problemas-comuns-4/</guid><description>&lt;div class='post'>
Precisamos estar atento que as variáveis de ambiente de &lt;a href="http://focalinux.cipsga.org.br/guia/avancado/ch-pers.htm">localização &lt;/a>podem atrapalhar, e muito, o comportamento de algumas &lt;a href="http://aurelio.net/er/">expressões regulares&lt;/a>.&lt;br />&lt;br />Por exemplo, se eu quero encontrar uma palavra que começe com a e termine com o (ex: ação)&lt;br />&lt;pre>&lt;code>$ cat arquivo&lt;br />luz, camera, ação&lt;br />$ grep -oE 'a\w+o' arquivo # nao mostra nada!&lt;/code>&lt;/pre>&lt;br />Antes de sair dizendo que o linux, grep ou as expressões regulares não prestam, vamos testar o mesmo comando no nosso 'idioma'&lt;br />&lt;pre>&lt;code>$ LC_ALL=pt_BR grep -oE 'a\w+o' arquivo&lt;br />ação&lt;/code>&lt;/pre>&lt;br />Ahá! Agora vamos ver um exemplo mais interessante:&lt;br />&lt;pre>&lt;code>$ tr '[:lower:]' '[:upper:]' &lt; arquivo&lt;br />LUZ, CAMERA, AçãO&lt;br />$ LC_ALL=pt_BR tr '[:lower:]' '[:upper:]' &lt; arquivo&lt;br />LUZ, CAMERA, AÇÃO&lt;/code>&lt;/pre>&lt;br />Perceberam como a variavel altera o comportamento das ERs? &lt;br />&lt;br />Como ultima dica: sempre que precisarem comparar textos independente da 'caixa' (se maiúscula ou minúscula), usem os recursos de ignorecase da ferramenta utilizada. Converter um texto todo para minúscula pode não apenas ser afetado pela localização como existem idiomas onde alguns caracteres não tem o exato correspondente entre uma caixa e outra como nós pensamos -- é o caso do idioma Turco, onde o 'i' maiúsculo não é 'I'. E, principalmente, não tente fazer &lt;a href="http://worsethanfailure.com/Articles/Extra-Sensitive-Case-Insensitivity.aspx">isso&lt;/a>.&lt;br />&lt;br />Mais informações em 'man locale' ;-)&lt;/div></description></item><item><title>Resolvendo Problemas Comuns 3 - missing separator</title><link>http://pacman.blog.br/blog/2007/07/26/resolvendo-problemas-comuns-3-missing/</link><pubDate>Thu, 26 Jul 2007 11:44:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/07/26/resolvendo-problemas-comuns-3-missing/</guid><description>&lt;div class='post'>
O &lt;a href="http://www.gnu.org/software/make/manual/make.html">make &lt;/a>é um comando incrivelmente poderoso, principalmente para programadores, permitindo que tarefas sejam organizadas de acordo com dependências, por exemplo.&lt;br />&lt;br />Um caso básico seria &lt;span style="font-style:italic;">construir &lt;/span>um grande programa, composto de diversos arquivos-fonte. O Makefile permite que vc &lt;span style="font-style:italic;">compile &lt;/span>apenas os arquivos que vc alterou desde o ultimo &lt;span style="font-style:italic;">build&lt;/span>, por exemplo, comparando o &lt;span style="font-style:italic;">timestamp &lt;/span>do fonte com o codigo objeto gerado.&lt;br />&lt;br />Bom, ai um Makefile poderoso foi editado num editor de texto profissional e, na hora de testar, nos deparamos com:&lt;br />&lt;pre>&lt;code>$ make &lt;br />Makefile:3: *** missing separator (did you mean TAB instead of 8 spaces?). Stop.&lt;br />&lt;br />$ cat Makefile # nome padrão de arquivo para o make.&lt;br /># um makefile comum&lt;br />all:&lt;br /> @echo "oi mundo"&lt;/code>&lt;/pre>&lt;br />&lt;br />Puxa, parece tudo certo... entretanto ai vai um pequeno detalhe: para cada &lt;span style="font-style:italic;">target&lt;/span> do makefile, os comandos que vem a seguir devem começar por um TAB (alias a mensagem de erro é bem clara nesse sentido, certo?). Vamos conferir:&lt;br />&lt;br />&lt;pre>&lt;code>$ cat -A Makefile # é mais pontente que o -v&lt;br /># um makefile comum$&lt;br />all:$&lt;br /> @echo "oi mundo"$&lt;/code>&lt;/pre>&lt;br /> &lt;br />Tcharam! Se a linha do echo iniciasse com um TAB, como deveria ser, apareceria um ^I no inicio da linha. Provavelmente a origem disso é um editor de texto que transforma os TABS em 8 espaços por questões estéticas. Vamos corrigir o Makefile?&lt;br />&lt;br />&lt;pre>&lt;code>$ sed -i 's/^\ \{8\}/\t/' Makefile&lt;br />$ cat -A Makefile&lt;br /># um makefile comum$&lt;br />all:$&lt;br />^I@echo "oi mundo"$&lt;br />$ make&lt;br />oi mundo&lt;/code>&lt;/pre>&lt;br />&lt;br />Pronto, basta substituir os espaços por TAB. Outra solução corrigir em um editor de textos mas sem a opção de expansão dos TABs -- no vim basta fazer&lt;br />&lt;br />&lt;pre>:set noexpandtab&lt;/pre>&lt;br />&lt;br />e editar numa boa.&lt;/div></description></item><item><title>Resolvendo Problemas Comuns 1 - Permission denied</title><link>http://pacman.blog.br/blog/2007/07/26/resolvendo-problemas-comuns-1/</link><pubDate>Thu, 26 Jul 2007 11:12:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/07/26/resolvendo-problemas-comuns-1/</guid><description>&lt;div class='post'>
Não é incomum, quando não temos experiência em shell, passar por uma situação dessas:&lt;br />&lt;br />&lt;pre>&lt;code>$ ./script.sh&lt;br />-bash: ./script.sh: Permission denied&lt;/code>&lt;/pre>&lt;br />&lt;br />Antes de sair olhando se há algo errado com o script, vamos analisar a mensagem de erro em pt_BR: &lt;span style="font-weight:bold;">Permissão negada&lt;/span>. Diferente de outros sistemas operacionais, no mundo *nix o que faz de um arquivo um programa executável não é a sua extensão e sim as suas &lt;span style="font-weight:bold;">permissões&lt;/span>.&lt;br />&lt;br />Resumidamente, existem 3 permissões básicas quando se trata de arquivos: ler, escrever e (finalmente) executar (representado pelas letras r,w e x, respectivamente). Isto é o que impede um usuário de conseguir ler os documentos de outro, por exemplo. Então, um programa, para ser executado, precisa ter esta permissão correspondente, e ai entra o comando &lt;a href="http://focalinux.cipsga.org.br/guia/iniciante/ch-perm.htm#s-perm-chmod">chmod&lt;/a>.&lt;br />&lt;br />&lt;pre>&lt;code>$ ls -l script.sh&lt;br />-rw-r--r-- 1 peczenyj users 22 2007-07-26 11:08 script.sh&lt;br />$ chmod +x script.sh # vamos ativar o bit de execução (x)&lt;br />$ ls -l script.sh&lt;br />-rw&lt;span style="font-weight:bold;">x&lt;/span>r-xr-x 1 peczenyj users 22 2007-07-26 11:08 &lt;span style="font-weight:bold;">./script.sh&lt;/span>&lt;br />$ ./script.sh #agora sim!!!&lt;br />oi&lt;/code>&lt;/pre>&lt;br />&lt;br />Problema resolvido.&lt;/div></description></item><item><title>Resolvendo Problemas Comuns 2 - bad interpreter</title><link>http://pacman.blog.br/blog/2007/07/26/resolvendo-problemas-comuns-2-bad/</link><pubDate>Thu, 26 Jul 2007 11:07:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/07/26/resolvendo-problemas-comuns-2-bad/</guid><description>&lt;div class='post'>
Seguindo na nossa sessão de dicas, quem nunca passou por isso?&lt;br />&lt;br />&lt;pre>&lt;code>$ ./script.sh&lt;br />: bad interpreter: No such file or directory&lt;br />&lt;br />$ cat script.sh&lt;br />#!/bin/bash&lt;br />echo "oi"&lt;/code>&lt;/pre>&lt;br /> - Hein? Mas está tudo certo, eu tenho um &lt;span style="font-weight:bold;">/bin/bash&lt;/span>, o que está acontecendo?&lt;br />&lt;br />Bom, vamos ver mais de perto:&lt;br />&lt;pre>&lt;code>$ cat -v script.sh # 'show nonprinting'&lt;br />#!/bin/bash^M&lt;br />echo "oi"^M&lt;/code>&lt;/pre>&lt;br />&lt;br />Ahá! Tem um ^M no final das linhas atrapalhando. &lt;br /> - Mas o que é isso?&lt;br />Muito provavelmente a origem desde script é uma maquina windows. A explicação é o caracter &lt;a href="http://en.wikipedia.org/wiki/Newline">newline&lt;/a>. O windows precisa de 2 caracteres para simbolizar o fim de uma linha em um arquivo texto puro, a dupla \r\n (veja link para a wikipedia), porém os *nix não precisam do \r -- que o cat gentilmente mostrou como um ^M. Este caracter a mais atrapalha o interpretador, que não recebe um /bin/bash e sim /bin/bash\r -- e isso realmente não existe.&lt;br />&lt;br />Como resolver? Existem dois programas para este fim: unix2dos e dos2unix (as vezes aparecem como unixtodos e dostounix) que convertem os finais de linha em casos como este. Se vc abrir um arquivo texto do *nix em um bloco de texto vai ver todas as quebras de linha substituidas por um quadrado preto e todas as linhas em uma só.&lt;br />&lt;br />Caso vc não tenha um programa conversor, pode usar o SED&lt;br />&lt;pre>&lt;code>$ sed -i 's/\r$//' script.sh&lt;br />$ ./script.sh&lt;br />oi&lt;/code>&lt;/pre>&lt;br />&lt;br />O tr também poderia ser usado, mas não é tão amigável.&lt;br />&lt;pre>&lt;code>$ tr -d '\r' &lt; script.sh > novo_script.sh&lt;/code>&lt;/pre>&lt;br />&lt;br />Este detalhe pode ser muito importante um dia!&lt;/div>
&lt;h2>Comments&lt;/h2>
&lt;div class='comments'>
&lt;div class='comment'>
&lt;div class='author'>arpapa&lt;/div>
&lt;div class='content'>
Pode também converter usando o comando dos2unix script.sh que funciona legal.&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Rioges&lt;/div>
&lt;div class='content'>
Resolveu o meu problema, muito obrigado pela dica!!&lt;/div>
&lt;/div>
&lt;/div></description></item><item><title>Calculando Números Primos usando Shell</title><link>http://pacman.blog.br/blog/2007/07/26/calculando-nmeros-primos-usando-shell/</link><pubDate>Thu, 26 Jul 2007 01:48:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/07/26/calculando-nmeros-primos-usando-shell/</guid><description>&lt;div class='post'>
Será possivel determinar se um número é primo, ou não, usando o bom e velho shell?&lt;br />&lt;br />A resposta está no comando &lt;span style="font-weight:bold;">factor&lt;/span>&lt;br />&lt;br />&lt;pre>&lt;code>seq 1 250 | factor | awk -F \: '$1 == $2{ print $1}' | column -x&lt;br />2 3 5 7 11 13 17 19 23 29&lt;br />31 37 41 43 47 53 59 61 67 71&lt;br />73 79 83 89 97 101 103 107 109 113&lt;br />127 131 137 139 149 151 157 163 167 173&lt;br />179 181 191 193 197 199 211 223 227 229&lt;br />233 239 241&lt;/code>&lt;/pre>&lt;br />&lt;br />A ideia é simples: se um número é primo ele possui apenas um único fator -- ele mesmo. Basta detectar esses casos via awk (ou grep, sed, existem varias formas). Usei aqui o &lt;span style="font-weight:bold;">seq&lt;/span> para gerar uma seqüência e o &lt;span style="font-weight:bold;">column &lt;/span>para tabular os resultados.&lt;/div></description></item><item><title>Identificando linhas repetidas em varios arquivos</title><link>http://pacman.blog.br/blog/2007/07/26/identificando-linhas-repetidas-em/</link><pubDate>Thu, 26 Jul 2007 00:10:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/07/26/identificando-linhas-repetidas-em/</guid><description>&lt;div class='post'>
Vamos imaginar dois arquivos bem simples e tres formas de identificar as linhas que aparecem em ambos:&lt;br />&lt;br />&lt;pre>&lt;code>$ cat arq1&lt;br />oi&lt;br />awk&lt;br />ciencia&lt;br />oi zoi&lt;br />&lt;br />$ cat arq2&lt;br />luxo&lt;br />awk&lt;br />oi&lt;br />luxo&lt;/code>&lt;/pre>&lt;br />&lt;br />Simples de perceber que as linhas 'oi' e 'awk' se repetem. Poderiamos pensar em uma poderosa união de sort + uniq &lt;br />&lt;pre>&lt;code>$ sort &lt;(sort arq1 | uniq) &lt;(sort arq2 | uniq) | uniq -d&lt;br />awk&lt;br />oi&lt;/code>&lt;/pre>&lt;br />&lt;br />Ou podemos abordar arrays em AWK (elegante, não?)&lt;br />&lt;pre>&lt;code>$ awk 'NR==1{ base=FILENAME } &lt;br />base == FILENAME {linhas[$0]++}&lt;br />base != FILENAME &amp;&amp; linhas[$0] { print }' arq1 arq2&lt;br />awk&lt;br />oi&lt;/code>&lt;/pre>&lt;br />&lt;br />Ou podemos usar o bom e velho grep:&lt;br />&lt;pre>&lt;code>$ grep -xf arq1 arq2&lt;br />awk&lt;br />oi&lt;/code>&lt;/pre>&lt;br />Qual a melhor abordagem? Ai depende de cada um :)&lt;br />&lt;br />Veja toda a aula que deu origem à estes scritps &lt;a href="http://br.groups.yahoo.com/group/shell-script/message/23362">aqui&lt;/a>.&lt;/div>
&lt;h2>Comments&lt;/h2>
&lt;div class='comments'>
&lt;div class='comment'>
&lt;div class='author'>Tiago Peczenyj&lt;/div>
&lt;div class='content'>
Denis, mantive os seus dois comentarios, apesar de serem semelhantes.&lt;BR/>&lt;BR/>Saca só, se pensarmos em 16 milhões de linhas, temos q pensar exatamente no que queremos. se for para encontrar as linhas exatas, talvez o grep seja mais rápido, porém acredito que vai ter muito acesso a disco.&lt;BR/>&lt;BR/>Se separarmos os arquivos em partes, de acordo com os caracteres iniciais, acho que a pesquisa pode ficar bem mais rapida -- se estiverem ordenados então vai q é um tapa.&lt;BR/>&lt;BR/>Ou talvez seja o momento de pensar em algoritmos mais complexos :)&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Denis&lt;/div>
&lt;div class='content'>
Imagino que para um busca menor de 16milhoes a melhor seria o grep, pois nao utiliza os redirects como no caso do UNIQ.&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Denis&lt;/div>
&lt;div class='content'>
Imagino que para um busca menor de 16milhoes a melhor seria o grep, pois nao utiliza os redirects como no caso do SORT. Se nao o AWK.&lt;/div>
&lt;/div>
&lt;/div></description></item><item><title>Baixando musicas do iJigg</title><link>http://pacman.blog.br/blog/2007/07/18/baixando-musicas-do-ijigg/</link><pubDate>Wed, 18 Jul 2007 14:54:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/07/18/baixando-musicas-do-ijigg/</guid><description>&lt;div class='post'>
O &lt;a href="http://www.ijigg.com">iJigg&lt;/a> é um youtube de mp3, basicamente. É interessante para trocar músicas ou mesmo colocar um pequeno player no seu site, como este:&lt;br />&lt;object width="315" height="80">&lt;param name="movie" value="http://www.ijigg.com/jiggPlayer.swf?songID=V2DA7ADPD&amp;Autoplay=0">&lt;param name="scale" value="noscale" />&lt;param name="wmode" value="transparent">&lt;embed src="http://www.ijigg.com/jiggPlayer.swf?Autoplay=0&amp;songID=V2DA7ADPD" width="315" height="80" scale="noscale" wmode="transparent">&lt;/embed>&lt;/object>&lt;br />&lt;br />Escolhi a musica &lt;a href="http://www.ijigg.com/songs/V2DA7ADPD">Surfista Calhorda&lt;/a>, dos Replicantes. Conheci este site graças a esta &lt;a href="http://www.dicas-l.com.br/dicas-l/20070718.php">dica&lt;/a> do dicas-l.&lt;br />&lt;br />Como todo bom nerd, decidi melhorar a dica, provendo um script para isso.&lt;br />&lt;br />&lt;pre>&lt;code>#!/bin/bash&lt;br />[ -z "${1}" ] &amp;&amp; { echo "usage: $0 &lt; ijigg URL | ID >" ; exit 1 ; }&lt;br />ID=${1##*/}&lt;br />CMD='/Location\|Title/{s/&lt;[^>]\+>//g;p}'&lt;br />URL="http://www.ijigg.com/cgi-bin/loadSongData.cgi?songID=${ID}"&lt;br />&lt;br />set - $( wget -q -O - "${URL}" | sed -n "${CMD}" | tr '\n ' '\t_' )&lt;br />&lt;br />wget ${1} -O "${2%.mp3}.mp3"&lt;/code>&lt;/pre>&lt;br />&lt;br />Ao executar e passar a URL ou ID da música como argumento, eu faço uma busca no site atras de informações sobre a mesma (veja variavel URL). Esta consulta é um xml que retorna a localização do arquivo mp3 e do seu nome. Faço uns malabarismos com SED -- que nem são tão complicados assim -- e obtenho a url direta para baixar o arquivo e o seu nome em um bom formato (troco os espaços do nome por '_' -- para permanecer os espaços no nome tem q fazer mais uns malabarismos...).&lt;br />&lt;br />Nesse caso:&lt;pre>$ ./ijigg.sh http://www.ijigg.com/songs/V2DA7ADPD&lt;br />--15:10:05-- http://staticmdb-001.ijigg.com/songdata04/...&lt;br /> => `Replicantes_-_Surfista_calhorda.mp3'&lt;br />...&lt;br />15:10:55 (33.26 KB/s) - `Replicantes_-_Surfista_calhorda.mp3' saved&lt;/pre>&lt;br />Agora basta ouvir no seu player preferido.&lt;/div></description></item><item><title>Bases Numericas em Bash</title><link>http://pacman.blog.br/blog/2007/07/12/bases-numericas-em-bash/</link><pubDate>Thu, 12 Jul 2007 11:49:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/07/12/bases-numericas-em-bash/</guid><description>&lt;div class='post'>
Com Bash, podemos representar números nas mais variadas bases, desde &lt;a href="http://en.wikipedia.org/wiki/Base2">2&lt;/a> até &lt;a href="en.wikipedia.org/wiki/Base64">64&lt;/a> usando o operador # como no exemplo abaixo:&lt;pre>&lt;code>&lt;br />X=101 &lt;br />for BASE in 2 8 10 16 32 64 ; do &lt;br /> echo "$X na base $BASE eh $(( ${BASE}#${X} ))" # conversao pra decimal&lt;br />done&lt;br />101 na base 2 eh 5&lt;br />101 na base 8 eh 65&lt;br />101 na base 10 eh 101&lt;br />101 na base 16 eh 257&lt;br />101 na base 32 eh 1025&lt;br />101 na base 64 eh 4097 &lt;br />&lt;br />echo $((16#FF)) $((32#V))&lt;br />255 31&lt;br />&lt;br />echo $((64#z)) $((64#Z)) $((64#@)) $((64#_)) # atenção nos 2 ultimos!&lt;br />35 61 62 63&lt;br />&lt;/code>&lt;/pre>&lt;br />Além de ser possível usar a notação de octal e hexa do C (iniciar a expressão com 0 e 0x, respectivamente)&lt;pre>&lt;code>echo $((10)) $(( 010 )) $(( 0x10 )) $((10 + 010 + 0x10))&lt;br />10 8 16 34&lt;code>&lt;/pre>&lt;br />Bastante útil para pequenas conversões. Agora se quisermos converter um numero de uma base qualquer para outra, o nosso amigo &lt;span style="font-weight:bold;">bc&lt;/span> pode servir:&lt;br />&lt;br />&lt;pre>&lt;/code>bc &lt;&lt;&lt; 'ibase = 8 ; obase = 16 ; 1027'&lt;br />2A3&lt;/code>&lt;/pre>&lt;br />Onde ibase é a base de entrada (input) e a obase é a de saída (output). A diferença fica nas bases muito altas (32 ou 64) onde não são usados os caracteres minúsculos, maiusculos e especiais.&lt;br />&lt;br />Esta dica foi tirada do &lt;a href="http://tldp.org/LDP/abs/abs-guide.pdf">Advanced Bash Scripting Guide&lt;/a>.&lt;br />&lt;br />&lt;!-- INICIO DO CODIGO DO CONTADOR DE VISITAS 2W.COM.BR -->&lt;br />&lt;img src="http://www.2w.com.br/imgcontador.php?p=e3ca6d6d" alt="Contador de visitas" border=0>&lt;br />&lt;!-- FIM DO CODIGO DO CONTADOR DE VISITAS 2W.COM.BR -->&lt;/div>
&lt;h2>Comments&lt;/h2>
&lt;div class='comments'>
&lt;div class='comment'>
&lt;div class='author'>Tiago Peczenyj&lt;/div>
&lt;div class='content'>
Ola!&lt;BR/>&lt;BR/>Se vc prestar atenção eu coloquei um comentário que informava a conversão para a base decimal pois achei q, se colocasse o 'na base 10' no final de cada linha poderia ficar um pouco poluido. Pelo visto ficou é confuso.&lt;BR/>&lt;BR/>agora, 101 em hexa é 257 sim, uma vez que 100 significaria, nesse caso, 1 x 16^2 -- 256. Vou postar mais sobre o assunto ai e vai vamos chegar a um consenso ;-)&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>naoliv&lt;/div>
&lt;div class='content'>
Hum... comentando com um amigo meu eu acho que você quis dizer:&lt;BR/>&lt;BR/>101 na base 2 eh 5 na base 10&lt;BR/>&lt;BR/>101 na base 8 eh 65 na base 10&lt;BR/>&lt;BR/>101 na base 10 eh 101 na base 10&lt;BR/>&lt;BR/>101 na base 16 eh 257 na base 10&lt;BR/>&lt;BR/>101 na base 32 eh 1025 na base 10&lt;BR/>&lt;BR/>101 na base 64 eh 4097 na base 10&lt;BR/>&lt;BR/>Faltou os "na base 10" :-)&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>naoliv&lt;/div>
&lt;div class='content'>
Isso tá certo?&lt;BR/>Como que o número pode ser 5 na base 2? (se só existem os caracteres 0 e 1)&lt;BR/>&lt;BR/>101 em hexa (base 16), por exemplo, é 65 e não 257.&lt;BR/>&lt;BR/>Ou eu entendi errado o seu post?&lt;/div>
&lt;/div>
&lt;/div></description></item><item><title>Youtube Downloader 2.0</title><link>http://pacman.blog.br/blog/2007/07/06/youtube-downloader-20/</link><pubDate>Fri, 06 Jul 2007 15:25:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/07/06/youtube-downloader-20/</guid><description>&lt;div class='post'>
A versão 1.0 foi até pro &lt;a href="http://www.dicas-l.com.br/dicas-l/20070705.php">Dicas-L&lt;/a>. Graças a esta exposição percebi que o script é muito útil para quem não tem um plug-in flash (que preste) no &lt;span style="font-style:italic;">browser&lt;/span>. É o caso do pessoal que usa &lt;a href="en.wikipedia.org/wiki/BeOS">Beos&lt;/a>, por exemplo. &lt;br />&lt;br />Reduzi o número de linhas, usei a &lt;a href="http://www.aurelio.net/shell/canivete.html#expansao">expansão de variáveis&lt;/a> do bash para algumas substituições simples e agora vc pode informar o nome do arquivo que vc quer salvar, senão será usado aquele nada pratico id. A extensão é flv que pode ser visualizado pelo &lt;span style="font-style:italic;">mplayer &lt;/span>ou convertido pra mpeg.&lt;br />&lt;br />&lt;pre>$ ./script.sh endereço_do_video nome_do_video&lt;/pre>&lt;br />Eis o código&lt;br />&lt;pre>&lt;code>#!/bin/bash&lt;br /># youtube downloader&lt;br />test -n "${1}" || { echo -e "Missing url or id!\nUsage: ${0} &amp;lt;url | id&amp;gt; [filename]" ; exit 1; }&lt;br />&lt;br />set - ${1/*=} ${2:-${1/*=}} "http://www.youtube.com/watch?v=${1/*=}" 'video_id=.+&amp;t=[^\"&amp;]+'&lt;br /> &lt;br />wget -O "${2%.flv}.flv" "${3%/*}/get_video?$(wget -qO - "${3}" | grep -oE "${4}" | sed '1q')" &lt;br />&lt;/code>&lt;/pre>&lt;br />&lt;br />Tentei usar o &lt;span style="font-weight:bold;">curl &lt;/span>e não consegui. Quem quiser tentar, faça um curl -I na url final e veja os cabeçalhos -- não sei como ir para o 'Location'. O wget faz isso numa boa, mas seria interessante ter a opção com o curl.&lt;br />&lt;br />O que seria mais interessante? Baixar uma lista de videos? Baixar os X primeiros videos que aparecem em uma dada pesquisa?&lt;/div></description></item><item><title>Parâmetros em Shell Script</title><link>http://pacman.blog.br/blog/2007/07/02/parmetros-em-shell-script/</link><pubDate>Mon, 02 Jul 2007 22:46:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/07/02/parmetros-em-shell-script/</guid><description>&lt;div class='post'>
Meu primeiro artigo, resultado de uma boa noite de insônia.&lt;br />&lt;br />Direto do CentOSBR: &lt;a href="http://centosbr.org/modules/smartsection/item.php?itemid=108">Parâmetros no Shell&lt;/a>.&lt;br />&lt;br />Estou enrolando outros textos tem tempo: vamos ver se agora eu continuo.&lt;/div></description></item><item><title>Youtube Downloader</title><link>http://pacman.blog.br/blog/2007/07/02/youtube-downloader/</link><pubDate>Mon, 02 Jul 2007 10:26:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/07/02/youtube-downloader/</guid><description>&lt;div class='post'>
Cerca de um ano atras eu pesquisei uma forma de fazer o download automatico de videos do youtube informando o id ou a url inteira. Ele é bem didático, basta ser um pouco nerd e conhecer um pouco de expressões regulares (alias o livro do Aurelio está em &lt;a href="http://aurelio.wordpress.com/2007/06/28/descontao-livro-saindo-por-menos-de-20-reais/">promoção&lt;/a>).&lt;br />&lt;br />Minha inspiração para postar este script veio desta &lt;a href="http://br-linux.org/linux/videos-do-youtube-no-lynx-em-ascii">notícia&lt;/a>, onde Warren Harding baixou um vídeo usando o Lynx e usou o Mplayer para exibir o vídeo no modo &lt;span style="font-style:italic;">ASCII&lt;/span>. O resultado é insano, porém divertido.&lt;br />&lt;br />&lt;pre>&lt;code>#!/bin/bash&lt;br /># youtube downloader&lt;br /># usage: script &lt;url or video_id>&lt;br /># YouTube URL: http://www.youtube.com/watch?v=[video_id] &lt;br />&lt;br />[ -z "${1}" ] &amp;&amp; { echo 'Error! Missing url or video_id!' ; exit 1 ; }&lt;br />&lt;br />URL="http://www.youtube.com"&lt;br />&lt;br /># download link: http://youtube.com/get_video?video_id=[video_id]&amp;t=[t_id]&amp;...&lt;br />&lt;br />DOWNLOAD=`wget -qO - "${URL}/watch?v=${1/*=}" | grep -oE 'video_id=.*&amp;t=[^\"&amp;]*' | head -1`&lt;br />&lt;br />wget -O "${1/*=}.flv" "${URL}/get_video?${DOWNLOAD}"&lt;/code>&lt;/pre>&lt;br />&lt;br />Eu poderia ter feito tudo em uma unica linha usando xargs, porém ficaria um pouco poluído para publicar neste humilde blog, mas fica aí a dica.&lt;/div></description></item><item><title>Classificação do Brasileiro via Shell Script</title><link>http://pacman.blog.br/blog/2007/06/25/classificao-do-brasileiro-via-shell/</link><pubDate>Mon, 25 Jun 2007 14:07:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/06/25/classificao-do-brasileiro-via-shell/</guid><description>&lt;div class='post'>
Querendo saber a classificação do seu time no campeonato brasileiro de 2007.&lt;br />&lt;br />O bom e velho &lt;b>lynx + grep&lt;/b> resolve.&lt;br />&lt;br />&lt;pre>&lt;code>$ URL=http://esportes.terra.com.br/futebol/brasileiro2007/classificacao/&lt;br />$ lynx --dump ${URL} | grep '%'&lt;br />&lt;br /> Colocação Time PG J V E D GP GC SG %&lt;br /> 1º Botafogo 17 7 5 2 0 18 7 11 81%&lt;br /> 2º Paraná 14 7 4 2 1 14 9 5 67%&lt;br /> 3º São Paulo 13 7 4 1 2 7 2 5 62%&lt;br /> 4º Goiás 12 7 4 0 3 13 9 4 57%&lt;br /> Fluminense 12 7 3 3 1 11 6 5 57%&lt;br /> Corinthians 12 6 3 3 0 7 2 5 67%&lt;br /> 7º Atlético-PR 11 7 3 2 2 12 10 2 52%&lt;br /> Atlético-MG 11 7 3 2 2 11 9 2 52%&lt;br /> Vasco 11 7 3 2 2 11 10 1 52%&lt;br /> 10º Cruzeiro 10 7 3 1 3 16 15 1 48%&lt;br /> Figueirense 10 7 3 1 3 13 14 -1 48%&lt;br /> 12º Grêmio 9 7 3 0 4 5 12 -7 43%&lt;br /> 13º Palmeiras 8 7 2 2 3 9 12 -3 38%&lt;br /> 14º Juventude 7 7 2 1 4 9 11 -2 33%&lt;br /> Internacional 7 7 2 1 4 8 12 -4 33%&lt;br /> Santos 7 7 2 1 4 7 11 -4 33%&lt;br /> 17º Flamengo 6 6 1 3 2 11 15 -4 33%&lt;br /> 18º Sport 5 7 1 2 4 9 13 -4 24%&lt;br /> Náutico 5 7 1 2 4 9 15 -6 24%&lt;br /> 20º América-RN 4 7 1 1 5 6 12 -6 19%&lt;/code>&lt;/pre>&lt;/div>
&lt;h2>Comments&lt;/h2>
&lt;div class='comments'>
&lt;div class='comment'>
&lt;div class='author'>Tiago Peczenyj&lt;/div>
&lt;div class='content'>
O link de 2007 tambem serve, o terra redireciona para o brasileirão atual :)&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>J. F. Mitre&lt;/div>
&lt;div class='content'>
O novo link para 2008 é:&lt;BR/>&lt;BR/>http://esportes.terra.com.br/futebol/brasileiro/2008/classificacao/&lt;BR/>&lt;BR/>funciona igualzinho ao anterior...&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Alexandre&lt;/div>
&lt;div class='content'>
Bacana isso ( de mais um flamenguista -triste- por aqui).&lt;/div>
&lt;/div>
&lt;div class='comment'>
&lt;div class='author'>Julio&lt;/div>
&lt;div class='content'>
Isso serve para mostrar como o Shell tem mil-e-uma utilidades. Script simples e rápido.&lt;BR/>&lt;BR/>Legal Tiago, ficará melhor ainda qdo o &lt;B>mengão&lt;/B> estiver em 1o. lugar. :)&lt;BR/>&lt;BR/>Julio&lt;BR/>:wq&lt;/div>
&lt;/div>
&lt;/div></description></item><item><title>The Linux Documentation Project</title><link>http://pacman.blog.br/blog/2007/06/21/linux-documentation-project/</link><pubDate>Thu, 21 Jun 2007 23:37:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/06/21/linux-documentation-project/</guid><description>&lt;div class='post'>
Muitos guias, tutoriais e Howtos &lt;a href="http://tldp.org/guides.html">aqui&lt;/a>.&lt;br />&lt;br />O 'Advanced Bash-Scripting Guide' do Mendel Cooper merece destaque especial -- um livro excelente, assim como o 'Bash Guide for Beginners' do Machtelt Garrels e o 'Linux From Scratch' Gerard Beekmans.&lt;br />&lt;br />Pesquisando um pouco conseguimos ate encontrar o &lt;a href="http://br.tldp.org/projetos/howto/arquivos/html/Portuguese-HOWTO/Portuguese-HOWTO.pt_BR.html">Linux Portuguese-HOWTO&lt;/a> escrito em 1997 pelo &lt;a href="http://unixmania.blogspot.com">CaSantos&lt;/a>.&lt;br />&lt;br />Boa leitura!&lt;/div></description></item><item><title>Canivete Multifunções do Shell</title><link>http://pacman.blog.br/blog/2007/06/19/canivete-multifunes-do-shell/</link><pubDate>Tue, 19 Jun 2007 11:35:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/06/19/canivete-multifunes-do-shell/</guid><description>&lt;div class='post'>
O Aurelio (verde) levou algum tempo juntando excelentes dicas sobre shell script que podem ser vistas aqui: o famoso &lt;a href="http://www.aurelio.net/shell/canivete.html">Canivete Suiço do Shell&lt;/a>.&lt;br />&lt;br />Facil de consultar, é extremamente útil para qualquer administrador ou usuário experiente de algum sabor de *nix (ou mesmo no Windows, via Cygwin).&lt;/div></description></item><item><title>Closures em Shell</title><link>http://pacman.blog.br/blog/2007/06/15/closures-em-shell/</link><pubDate>Fri, 15 Jun 2007 17:27:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/06/15/closures-em-shell/</guid><description>&lt;div class='post'>
Uma das coisas mais impressionantes (pelo menos para mim) da linguagem Ruby são os Closures:&lt;br />&lt;br />&lt;pre>&lt;code>$ ruby -e 'r=0...3 ; r.each { puts "oi"}&lt;br />oi&lt;br />oi&lt;br />oi&lt;/code>&lt;/pre>&lt;br />&lt;br />em um objeto do tipo Range eu tenho um método chamado each que recebe um bloco de código como argumento. Este bloco pode até ser parametrizado, por exemplo:&lt;br />&lt;br />&lt;pre>&lt;code>$ ruby -e 'r=0...3 ; r.each { |i| puts 2*i}'&lt;br />0&lt;br />2&lt;br />4&lt;/code>&lt;/pre>&lt;br />&lt;br />O que o metodo each faz é passar este bloco de código para 'dentro de si' e aplica-o em cada elemento do objeto 'range'. Pode ser para imprimir o resultado ou efetuar uma operação matemática, até mesmo substituindo um laço for simples. A verdade é que os Closures são bem mais do que isso e permitem fazer scripts bem interessantes.&lt;br />&lt;br />Sera que poderiamos ter o mesmo em BashScript ? Bem... vou simular aqui &lt;br />&lt;br />&lt;pre>&lt;code>$ each(){ &lt;br /> local F="${@}" &lt;br /> while read i ; do &lt;br /> set - $i &lt;br /> eval "${F}" &lt;br /> done &lt;br />}&lt;br />&lt;br />$ seq 3 | each '{ echo "encontrei $1" ; }'&lt;br />encontrei 1&lt;br />encontrei 2&lt;br />encontrei 3&lt;/code>&lt;/pre>&lt;br />&lt;br />Simples heim? Eu crio uma variavel local dentro de uma função e 'executo-a' para cada resultado via comando eval. Se este tipo de construção for util para alguem, fica aí a dica!&lt;/div></description></item><item><title>Avaliando Espaço em Disco</title><link>http://pacman.blog.br/blog/2007/06/13/avaliando-espao-em-disco/</link><pubDate>Wed, 13 Jun 2007 17:19:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/06/13/avaliando-espao-em-disco/</guid><description>&lt;div class='post'>
Um problema comum de qualquer administrador é o espaço em disco. As politicas de quotas geralmente resolvem boa parte destes problemas, é claro, mas nem sempre são suficientes.&lt;br />&lt;br />O caso: pensando de forma genérica, diversas pessoas criam diretórios de trabalho dentro do bom e velho/local e, com o passar do tempo, esta partição pode lotar e comprometer o trabalho de todos. Politicas de uso racional do espaço em disco podem ser aplicadas mas as vezes a coisa pode sair do controle -- nesse caso o prejuizo pode ser grande.&lt;br />&lt;br />Os diretorios possuem o seguinte formato:&lt;br />&lt;pre>/local/diretorio/algum_nome_identificador.vws&lt;/pre>&lt;br />&lt;br />Vamos recorrer ao bom e velho Shell-Script para investigar se existe algum problema em andamento!&lt;br />&lt;br />&lt;pre>$ df /local&lt;br />Filesystem 1K-blocks Used Available Use% Mounted on&lt;br />/dev/sdb1 35001508 11330452 21893064 35% /local&lt;/pre>&lt;br />&lt;br />Vejam só: apenas 35% da partição está sendo ocupada e isso não representa risco neste momento. Se estivesse acima de 80% alguma medida perventiva deveria ser tomada. Como podemos fazer este teste? Existem varias formas, vou usar o poder das expressões regulares para isso!&lt;br />&lt;br />&lt;pre>&lt;code>$ seq -f"%g%%" 10 5 100 | grep -E '(100|[89][0-9])%'&lt;br />&lt;br />80%&lt;br />85%&lt;br />90%&lt;br />95%&lt;br />100%&lt;/code>&lt;/pre>&lt;br />&lt;br />A expressão usada no grep casa com valores de porcentagem acima de 80% (inclusive), logo podemos usar em um teste simples&lt;br />&lt;br />&lt;pre>&lt;code> if df /local | grep -qE '(100|[89][0-9])%' ; then&lt;br /> echo '/local [quase] lotado!'&lt;br /> else&lt;br /> echo '/local seguro (menos de 80%)'&lt;br /> fi&lt;/code>&lt;/pre>&lt;br />&lt;br />Simples, não? Poderia ter usado os operadores &amp;&amp; e || mas não queria sacrificar a legibilidade do código.&lt;br />&lt;br />Agora vem a parte divertida: e se o /local estiver ficando cheio, vamos fazer o que?&lt;br />&lt;br />Quando vc não tem a responsabilidade de apagar arquivos desnecessários, o maximo que vc pode fazer é avisar os responsáveis. Elaborar um relatório com os 'problemas' encontrados e enviar por email usando shell script é simples.&lt;br />&lt;br />Vamos usar o du para calcular o espaço gasto em cada diretório e o sort para ordenar do maior para o menor tamanho total.&lt;br />&lt;br />&lt;pre>&lt;code>$ du -bs /local/diretorio/* 2>&amp;- | sort -nr &lt;br />3765643919 /local/diretorio/nonono001.vws&lt;br />2290883178 /local/diretorio/nonono002.vws&lt;br />2067295469 /local/diretorio/nonono003.vws&lt;br />932165874 /local/diretorio/nonono004.vws&lt;br />...&lt;br />267271 /local/viewstore1/nonono999.vws&lt;/code>&lt;/pre>&lt;br />&lt;br />Facil heim ? Se vc se dá ao trabalho de ler as man pages do du e do sort, basta fazer algumas experiências até obter o resultado que mais lhe agrada. Por exemplo, uma atitude interessante seria listar os X maiores diretórios e enviar por email para o administrador.&lt;br />&lt;br />&lt;pre>&lt;code>$ du -bs /local/diretorio/* 2>&amp;- | sort -nr | head -10 > /tmp/arquivo.log &lt;br />$ mailx -S "Lista dos 10 maiores diretorios" "administrador@server" &lt; /tmp/arquivo.log&lt;/code>&lt;/pre>&lt;br />&lt;br />Talvez vc pergunte o motivo pelo qual eu utilizo um arquivo temporário: caso o envio do email dê algum problema, é possivel recuperar a lista.&lt;br />&lt;br />Um script para rodar na cron e enviar o email de forma automatizada teria este formato:&lt;br />&lt;br />&lt;pre>&lt;code>#!/bin/bash&lt;br /># Autor: Tiago Peczenyj - 13/jun/2007&lt;br /># Script parametrizado para avaliar tamanho de alguns diretorios&lt;br />&lt;br />X=10&lt;br />DIR=/local/diretorio&lt;br />EMAIL=administrador@server&lt;br />SUBJECT="Lista dos ${X} maiores diretorios em $(date +"%Y%m%d" )"&lt;br />if df ${DIR} | grep -qE '(100|[89][0-9])%' ; then&lt;br /> du -bs ${DIR}/* 2>&amp;- | sort -nr | head -${X} > /tmp/arquivo.log &lt;br /> mailx -S "${SUBJECT}" ${EMAIL} &lt; /tmp/arquivo.log&lt;br />fi&lt;/code>&lt;/pre>&lt;br />&lt;br />O script parece simples, entretanto algo simples como informar o usuario dono de cada diretório é muito mais complexo. A minha solução foi esta:&lt;br />&lt;br />&lt;code>&lt;pre>paste -d '\t' &lt;(du -bs /local/viewstore1/* 2>&amp;-) \&lt;br />&lt;(ls -l /local/viewstore1 | awk '/^d/{print $3}') | awk '{&lt;br /> OFS="\t" ; print $1,$3,$2&lt;br />}'| sort -nr&lt;/code>&lt;/pre>&lt;/div></description></item><item><title>Um Caracter Inconveniente</title><link>http://pacman.blog.br/blog/2007/06/12/um-caracter-inconveniente/</link><pubDate>Tue, 12 Jun 2007 17:19:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/06/12/um-caracter-inconveniente/</guid><description>&lt;div class='post'>
Não é incomum passar pelo problema de tentar apagar um arquivo cujo nome começa com o caracter '-', como no exemplo abaixo:&lt;br />&lt;br />&lt;pre>&lt;code>$ rm -arquivo.txt&lt;br />rm: invalid option -- a&lt;/code>&lt;/pre>&lt;br />&lt;br />Não adianta proteger a string pois não é o Shell que atrapalha a ação, e sim o próprio programa que reconhece o símbolo - de uma forma diferente. O programa &lt;span style="font-weight:bold;">rm&lt;/span> aceita, alem de uma lista de arquivos para apagar, uma série de opções que modificam o seu funcionamento. As mais comuns são:&lt;br />&lt;br />&lt;pre>&lt;code> -f ignore nonexistent files, never prompt&lt;br /> -i prompt before any removal&lt;br /> -r remove the contents of directories recursively&lt;br /> -v explain what is being done&lt;/code>&lt;/pre>&lt;br />&lt;br />As opções normalmente pode ser colocadas em qualquer lugar da lista de parâmetros.&lt;br />&lt;br />&lt;pre>&lt;code>$ rm -v a.out&lt;br />removed `a.out'&lt;br />&lt;br />$ rm a.out -v &lt;br />removed `a.out'&lt;/code>&lt;/pre>&lt;br />&lt;br />Quem avalia os parâmetros normalmente é uma função chamada getopt (presente em várias linguagens, inclusive no Bash). Bom, vimos que o - é um caracter especial para o getopt, mas existe alguma forma de &lt;span style="font-weight:bold;">burlar&lt;/span> isso?&lt;br />&lt;br />Sim! O proprio getopt prove essa funcionalidade: o uso dos simbolos '--'. Eles interrompem a expansão de parâmetros e tudo o que vier &lt;span style="font-weight:bold;">depois&lt;/span> desses dois caracteres será interpretado literalmente pelo programa.&lt;br />&lt;br />Assim sendo:&lt;br />&lt;br />&lt;pre>&lt;code>$ rm -v -- -arquivo.txt&lt;br />removed `-arquivo.txt'&lt;/code>&lt;/pre>&lt;br />&lt;br />Esta dica está no help do comando rm e vale para todos os programas que usem getopts.&lt;/div>
&lt;h2>Comments&lt;/h2>
&lt;div class='comments'>
&lt;div class='comment'>
&lt;div class='author'>La Batalema Pitonisto&lt;/div>
&lt;div class='content'>
É Tiago,&lt;BR/>&lt;BR/>Nunca caí nessa do arquivo começado com sinal de menos, não por ser mais esperto que os outros, mas porque sou uma traça de manual. =)&lt;BR/>&lt;BR/>Basta um man rm para resolver o problema (foi o que fiz na primeira vez em que me deparei com um arquivo desses).&lt;BR/>&lt;BR/>Mas sabia que existe um livro que muitos chamam de «A Bíblia Negra do Hacker» (creio que a alcunha correta seria «o livreto negro de bolso do lammer»)? Esse livro apresenta a questão do «ataque» (ó! pretenção) onde o «atacante» (uf!) usa :> para criar arquivos começando com sinal de menos, cuja única forma de resolver o problema, segundo o livro, é mover todos os demais arquivos para outro diretório e apagar (argh!) o diretório onde estão os arquivos maliciosos.&lt;BR/>&lt;BR/>É de se escangalhar de rir&amp;hellip; um verdadeiro livreto de piadas sujas.&lt;BR/>&lt;BR/>[]'s&lt;BR/>Cacilhas&lt;/div>
&lt;/div>
&lt;/div></description></item><item><title>Ola Mundo!</title><link>http://pacman.blog.br/blog/2007/06/11/ola-mundo/</link><pubDate>Mon, 11 Jun 2007 16:42:00 -0300</pubDate><guid>http://pacman.blog.br/blog/2007/06/11/ola-mundo/</guid><description>&lt;div class='post'>
Quando aprendemos uma nova linguagem de programação, normalmente o primeiro exemplo é o famoso "Hello World!", ou seja, um pequeno código que imprime uma mensagem na tela do computador.&lt;br />&lt;br />Em C, ele seria assim:&lt;br />&lt;br />&lt;pre>&lt;code>/* Um comentário */&lt;br />#include &amp;lt;stdio.h&amp;gt;&lt;br />&lt;br />int main ()&lt;br />{&lt;br /> puts ("Hello world!");&lt;br /> return 0;&lt;br />}&lt;/code>&lt;/pre>&lt;br />&lt;br />As vezes o &lt;span style="font-weight:bold;">puts&lt;/span> é substituido pelo multifacetado &lt;span style="font-weight:bold;">printf&lt;/span> no exemplo, mas o efeito é o mesmo. Vejamos como seria em Java.&lt;br />&lt;br />&lt;pre>&lt;code>/* Comentarios, igual ao C */&lt;br />package Hello;&lt;br />&lt;br />public class HelloWorld {&lt;br /> public static void main(String[] args) {&lt;br /> System.out.println("Hello world");&lt;br /> }&lt;br /> }&lt;/code>&lt;/pre>&lt;br />&lt;br />As diferenças são várias, apesar da estrutura ser semelhante. Em C nós temos funções parametrizadas, enquanto em Java nós temos objetos (System.out) e métodos (println). &lt;br />&lt;br />Por fim, vamos ver um exemplo em Shell Script&lt;br />&lt;br />&lt;pre>&lt;code>#!/bin/bash&lt;br /># comentario&lt;br />echo "Hello World!"&lt;/code>&lt;/pre>&lt;br />&lt;br />Diferente de uma linguagem de programação, aqui o interpretador de comandos (normalmente) chama um programa capaz de escrever mensagens para o usuario. Ou seja, alguem ja escreveu um "Hello World!" genérico o suficiente para nós. &lt;br />&lt;br />Cada linguagem possui um propósito. Enquanto vc projeta sistemas operacionais e drivers em C, Java ocupa uma área no desenvolvimento de grandes sistemas corporativos enquanto o shell está presente na administração de determinadas tarefas de um servidor (normalmente rodando algum sabor de *nix). &lt;br />&lt;br />Não basta comparar um hello world, pois é preciso ver muito além da sintaxe e recursos da linguagem, mas normalmente se começa por ele.&lt;br />&lt;br />Outros exemplos podem ser encontrados &lt;a href="http://www.roesler-ac.de/wolfram/hello.htm">aqui&lt;/a>.&lt;br />&lt;br />Abraços&lt;/div></description></item></channel></rss>