shell-script-pt
[Top][All Lists]
Advanced

[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."
------------------------------


reply via email to

[Prev in Thread] Current Thread [Next in Thread]