Eis que a lista de shell script traz um bom desafio.
Galera, tenho o seguinte log.:
AAAA-------------campo_1-------------campo_2-----campo_3----campo_4----------
teste_1 371508787 371547453 38666 testetesteteste
BBBB-------------campo_1-------------campo_2-----campo_3----campo_4----------
teste_2 4625081503 4651313710 26232207 testetesteteste
Estou a tentar usar o awk com a seguinte função :
awk '$1~"teste_" {print $5";"$4}' teste > teste_.csv
a funcao busca realmente o que desejo:
$5 $4
testetesteteste 38666
testetesteteste 6232207
porem,, gostaria que seprasse da forma:
AAAA-------------
testetesteteste 38666
BBBB-------------
testetesteteste 26232207
Alguém tem uma dica de como fazer?
Ah... o bom e velho SED pode resolver isso$ sed -rn '/(^[^-]+-+).*/{s//\1/;h};
/^teste_/{s/.* ([^ ]+) +([^ ]+$)/\2 \1/;x;p;g;p}' arquivo.log
AAAA-------------
testetesteteste 38666
BBBB-------------
testetesteteste 26232207
Ok, ok, ta muito complicado, mas veja só:$ sed -rn '/^[^-]+-+/h;/^teste_/{x;p;g;p}' arquivo.log
AAAA-------------campo_1-------------campo_2-----campo_3----campo_4----------
teste_1 371508787 371547453 38666 testetesteteste
BBBB-------------campo_1-------------campo_2-----campo_3----campo_4----------
teste_2 4625081503 4651313710 26232207 testetesteteste
Vamos explicar
1) a opção -n serve para informar ao sed "imprima apenas quando eu mandar"
2) a opção -p serve para utilizar expressões regulares extendidas
(assim não preciso escapar o quantificador + , que significa "um ou
mais vezes", assim como os parentesis, para informar os grupos).
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
do AAAA------------- ... ).
Agora, quando eu encontro uma linha que começa com teste_ eu:
x) troco essa linha com a linha que esta na memória (a atual
'teste_...' vai, outra volta).
p) imprimo a linha que veio (AAAA---------- ...)
g) pego a linha da memória (teste_...)
p) imprimo a linha cachorrona
Só que não fica como vc quer. Ai vc precisa fazer a sacanagem:
se uma linha NÃO tem o que eu quero, então eu a manipulo habilmente
até que ela chegue ao que eu quero
Eu poderia ter usado varias tecnicas mas... uma vez com sed, podemos continuar nele.$ sed -rn '/(^[^-]+-+).*/{s//\1/;h};
/^teste_/{s/.* ([^ ]+) +([^ ]+$)/\2 \1/;x;p;g;p}' arquivo.log
eu transformei a primera ER em (minha_ER).* -- ou seja, criei um grupo para o que me interessa. basta fazer:s/(minha_ER).*/\1/
para que toda a linha seja reduzida ao que a minha ER casa. em outras palavras, eu apaguei o resto da linha.
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.
Vamos ver a versão AWK?$ awk '/^[^-]+-+/{match($0,/^[^-]+-+/); x=substr($0,1,RLENGTH)}
/^teste_/{print x,"\n"$5,$4}' arquivo.log
AAAA-------------
testetesteteste 38666
BBBB-------------
testetesteteste 26232207
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.
Aqui fala um pouco dessas duas funções: http://people.cs.uu.nl/piet/docs/nawk/nawk_92.html
Eu poderia ter resolvido dessa forma também$ awk '/^[^-]+-+/{sub(/-[^-]+.*$/,"-");x=$0}
/^teste_/{print x,"\n"$5,$4}' arquivo.log
AAAA-------------
testetesteteste 38666
BBBB-------------
testetesteteste 26232207
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.
AWK & SED são ferramentas sensacionais para esse tipo de problema ;-)
sábado, 26 de abril de 2008
Manipulando logs com AWK e SED
By
Tiago "PacMan" Peczenyj
às
14:41
2
comentários
domingo, 13 de abril de 2008
Um corretor ortográfico em gawk
Ano passado eu publiquei uma pequena nota sobre um pequeno corretor ortográfico feito em Python.
No artigo 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).
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.
Eu chamo de linha um statement completo do awk. Perceba que nenhuma linha dessas possui o separador de statement ; (ponto-e-virgula), exceto quando estou utilizando o for no estilo C.
# Usage: gawk -v word=something -f thisfile.awk [ big.txt [ big2.txt ... ]]
# Gawk version with 15 lines -- 04/13/2008
# Author: tiago (dot) peczenyj (at) gmail (dot) com
# Based on : http://norvig.com/spell-correct.html
function edits(w,max,candidates,list, i,j){
for(i=0;i< max ;++i) ++list[substr(w,0,i) substr(w,i+2)]
for(i=0;i< max-1;++i) ++list[substr(w,0,i) substr(w,i+2,1) substr(w,i+1,1) substr(w,i+3)]
for(i=0;i< max ;++i) for(j in alpha) ++list[substr(w,0,i) alpha[j] substr(w,i+2)]
for(i=0;i<= max ;++i) for(j in alpha) ++list[substr(w,0,i) alpha[j] substr(w,i+1)]
for(i in list) if(i in NWORDS) candidates[i] = NWORDS[i] }
function correct(word ,candidates,i,list,max,temp){
edits(word,length(word),candidates,list)
if (!asort(candidates,temp)) for(i in list) edits(i,length(i),candidates)
return (max = asorti(candidates)) ? candidates[max] : word }
BEGIN{ if (ARGC == 1) ARGV[ARGC++] = "big.txt" # http://norvig.com/big.txt
while(++i<=length(x="abcdefghijklmnopqrstuvwxyz")) alpha[i]=substr(x,i,1)
IGNORECASE=RS="[^"x"]+" }
{ ++NWORDS[tolower($1)] }
END{ print (word in NWORDS) ? word : "correct("word")=> " correct(tolower(word)) }Veja o script em funcionamento:
$ time gawk -v word=somethink -f spelling.awk
correct(somethink)=> something
real 0m4.862s
user 0m4.702s
sys 0m0.093s
By
Tiago "PacMan" Peczenyj
às
14:39
2
comentários