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
Ok, ok, ta muito complicado, mas veja só:
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.
eu transformei a primera ER em (minha_ER).* – ou seja, criei um grupo para o que me interessa. basta fazer:
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?
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
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 ;-)
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 ;-)
Acho que chegou a hora de limpar a minha ferrugem e reler o Advanced Bash Scripting Guide.
You produce some quite nice pearls inside the shell ;)
$ grep -B 1 teste_ arquivo.log | \
awk ‘/teste_/{print $5,$4; next} 1’ | \
sed -r ‘/^–$/d;s/(^[^-]+-+)[^-].*/\1/’
AAAA————-
testetesteteste 38666
BBBB————-
testetesteteste 26232207