[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [shell-script] sed emulando head -n 1 e tail -2 filtrando o meio
From: |
jimmy |
Subject: |
Re: [shell-script] sed emulando head -n 1 e tail -2 filtrando o meio |
Date: |
Sat, 20 Nov 2010 17:54:06 -0200 |
User-agent: |
Mutt/1.4.2.3i |
Saudações Julio,
On Thu, Nov 18, 2010 at 07:54:45PM -0200, Julio Quierati wrote:
>
>
> Olá Lista,
>
> Tenho um arquivo com o seguinte formato com n linhas conforme o modelo
> abaixo
>
> 0211070250520100928022505201025052010000031
>
> 10560704717499612301 0007415 7791259913
> 000772505201007410500020300019002000000000000 0000003R
>
> 10850704577499797055 0007499 8781000282
> 000872505201007504300005000007003870000000000 0000004R
>
> 10560700707499946523 0007115 7581070561
> 000752505201007515900002200005002000000000000 0000005R
>
> 20560700447199883145 0007115 4191057039
> 000412505201007541300004500006003000000000000 0000007R
>
> 10560700707199879410 0007515 7199752444
> 000712505201007501500021000020002000000000000 0000008R
> 20850700107191314938 0007199 1174803037
> 000112505201007583100003500005003110000000000 0000236R
>
> 10580700747199090110 0007915 7591982260
> 000752505201007284700011300010002790000000000 0000238R
>
> 90000312000000000000000000
>
> ^$ - linha em branco
>
> Preciso conservar a 1 e as 2 ultimas linhas e as demais que comecem com 2
> apagando as demais.
> Lembrando que ultima linha do arquivo é ^$ =D
>
> A saida esperada seria essa:
>
> 0211070250520100928022505201025052010000031
> 20560700447199883145 0007115 4191057039
> 000412505201007541300004500006003000000000000 0000007R
> 20850700107191314938 0007199 1174803037
> 000112505201007583100003500005003110000000000 0000236R
> 20560700447199883145 0007115 4191057039
> 000412505201007541300004500006003000000000000 0000007R
> 20850700107191314938 0007199 1174803037
> 000112505201007583100003500005003110000000000 0000236R
> 90000312000000000000000000
>
> ^$ - linha em branco
Há dados aqui que não encontrei na entrada. Você tem certeza que essa
saída é o resultado para a entrada mostrada acima?
>
> para as linhas que comecem com 2 foi tranquilo =D
> sed -i '{1p;/^2/!d}' arquivo.txt
As chaves são dispensáveis aqui.
>
> Mas e para conservar as 2 ultimas linhas ?
Sempre que ler uma linha, guarde-a no hold space, ao final, imprima a
linha atual mais a que ficou guardada.
$ sed '1p;/^2/p;${x;G};h;$!d;' arquivo.txt
${x;G};
Na última linha, inverta o pattern space com o hold space (isso é apenas
para não ter que inverter as linhas depois com "s/...") e anexe-os.
Precisamos fazer isso antes do comando "h" para manter a linha anterior.
$!d;
Apague todas as linhas, com excessão da última, do contrário o script
termina sem processar o "${..}"
>
> Procurando um pouco encontrei
> sed -e :a -e '{$q;N;3,$D;ba}' arquivo.txt
Nesse caso, tanto as chaves quanto o comando "$q" são dispensáveis, o
comando "N" já fará o trabalho do "$q" ao encontrar o final do arquivo.
>
> Mas nao consegui imprimir a 1 e filtrar o meio.
Tente fazer assim:
$ sed '1p;:oo;/^2/P;N;3,$D;b oo;' arquivo.txt
a impressão das linhas que começam com o número 2 ocorrerá antes das
concatenações, nos livrando de ter que trabalhar com situações onde as
mesmas linhas podem estar em qualquer lugar do patter space corrente,
podendo repetir a cada looping.
>
> Em awk consegui, depois de algum tempo procurando =D tail -2
>
> awk 'NR==1 {print};/^2/ {print};{y=x "\n" $0; x=$0};END{print y}'
> arquivo.txt
Você pode ir armazenando os dados em um array no bloco principal, no
bloco "END" você faz a impressão desse array para o mesmo arquivo que
processado.
$ awk
'NR==1{a[++i]=$0}/^2/{a[++i]=$0}{y=x"\n"$0;x=$0}END{for(j=1;j<=i;j++)print
a[j]>FILENAME;print y>FILENAME}' arquivo.txt
>
> Mas necessito da linda opcao -i do sed, awk tem algo parecido, vim?
Diferente do awk e do sed, o vim e o ed sabem o fim do arquivo e
deixarão você usar índices negativos, facilitando bastante o trabalho em
emular o tail com eles.
Por curiosidade, esse simples script em ed talvez também resolva o seu
caso:
$ ed -s arquivo.txt <<< $'2,$-2g/^[^2]/d\n2,$-2g/^[[:blank:]]*$/d\nw'
se o shell que você usar não tiver suporte ao "here strings" (<<<) use
$ echo -e ... | ed -s arquivo.txt
Usando o modo normal do vim, os comandos são praticamente os mesmos que
os do ed:
$ vim -c '2,$-2g/^[^2]/d' -c '2,$-2g/^[[:blank:]]*$/d' -c 'x' arquivo.txt
usando a linguagem interna do vim, a lógica será semelhante a usada com
no awk, só não iremos precisar armazenar os dados de interesse para
escrever no arquivo de volta.
Obs.[1]: Usei somente versões gnu para os comandos acima e talvez não
funcionem com versões diferentes e/ou proprietárias.
Obs.[2]: Assumi que a penúltima linha nunca será um linha iniciada com o
número 2, do contrário, será impresso duas vezes. Para resolver, antes
de imprimir essas linhas, teste se é a penúltima.
> Necessito de uma luz!
>
> Atenciosamente,
>
> Julio Quierati
> User Linux #492973
--
"Não manejo bem as palavras
Mas manipulo bem as strings."
------------------------------