<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Sed on Peczenyj's Blog</title><link>http://pacman.blog.br/categories/sed/</link><description>Recent content in Sed on Peczenyj's Blog</description><generator>Hugo</generator><language>en-us</language><lastBuildDate>Sat, 26 Apr 2008 14:41:00 -0300</lastBuildDate><atom:link href="http://pacman.blog.br/categories/sed/atom.xml" rel="self" type="application/rss+xml"/><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></channel></rss>