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

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [shell-script] SED: Inserir linhas entre dois paterns.


From: Rodrigo Tenorio
Subject: Re: [shell-script] SED: Inserir linhas entre dois paterns.
Date: Sun, 12 Oct 2014 00:12:19 -0300

Saudações, Ronaldo.

Camarada, obrigado pela explicação.

No primeiro caso eu passei pelo erro que você demonstrou. Mas somente agora que me dei conta do tamanho da besteira que fiz.
Bom. Devido ao erro de sintaxe tinha abandonado aquela tentativa e partido para a segunda do zero.

Testei sua sugestão.Tomarei a liberdade de usá-la.

Fato é que eu não conhecia o "&" na estrutura do "s///". Daí minha complicação.
Em testes, notei que ele reescreveu o pattern que ele substituiu. Aí realmente tudo se torna mais simples.

E gostei do esquema com o diff...

Muito obrigado!

Em 11 de outubro de 2014 23:23, Ronaldo Ferreira de Lima address@hidden [shell-script] <address@hidden> escreveu:
 

Saudações Rodrigo,

On Sat, Oct 11, 2014 at 09:46:44PM -0300, Rodrigo Tenorio address@hidden [shell-script] wrote:
[...]
> Tenho o seguinte cenário:
>
> cat >> teste << EOT
> LINHAS
> LINHAS
> AAA
> BBB
> LINHAS
> AAA
> EEE
> LINHAS
> LINHAS
> LINHAS
> EOT
>
> Preciso inserir as linhas BBB, CCC, DDD somente quando a próxima linha de AAA
> for EEE.
> Eu consegui localizar e imprimir com:
>
> # sed -n "/^AAA/g;{n;/^EEE/p}" teste
Há erros semânticos nesse sed-1liner:

1. '/^AAA/g' => procure por tudo o que começa com "AAA" e não faça
nada além disto.
2. '{n;' => para cada linha, descarte a atual e coloque a próxima
no pattern space.
2.1. '/^EEE/p}' => se a linha começar com "EEE", imprima.

Aplicando esse comando no exemplo acima, o resultado esperado não é
reproduzido porque o 1liner imprime "EEE" apenas se ele estiver em
linhas pares. Experimente exatamente o mesmo código com o seguinte
exemplo:

1
EEE
3
EEE
5
EEE
7

e você terá três "EEE" como saída.

> Mas ao trocar o "p" para "i BBB" recebo o seguinde retorno:
>
> # sed -n "/^AAA/g;{n;/^EEE/i BBB}" teste
> sed: -e expressão #1, caractere 0: `{' não terminada
> Acreditava que se eu conseguia imprimir o EEE, eu conseguiria adicionar
> conteúdo antes dele.
Aqui além do problema semântico, há problemas de sintaxe,
precisaria ser reescrito para que o comando "i" fique entre colchetes
(indicando um bloco de comando operando para um endereço), para manter o
1liner, ainda seria necessário utilizar dois '-e'.

> ...
> Bem. Depois de muito bater cabeça, cheguei no ponto em que o sed fez o que eu
> precisava...
>
> # sed -r ":a;/^AAA/{n;/^EEE/bc};n;ba;:c;i BBB" teste
>
> ... Mas ainda faltam inserir as linhas CCC e DDD. E isso eu consegui usando "i
> BBB \nCCC \nDDD".
>
> Destrinchando a coisa da maneira que entendi:
> :a # marcador e início de fluxo de ER.
> /^AAA/ # pesquisa pelo patern AAA que começa com um A, devido ao ^.
> {
> n # pula para a próxima linha.
> /^EEE/ # similar ao /^AAA/.
> bc # salto para o fluxo de ER "c": o "b" é o salto e o "c" é o endereço para
> onde ele vai saltar.
> }
> n # pula para a próxima linha.
> ba # similar ao "bc".
> :c # similar ao ":a".
> i BBB # o "i" insere cadeias de caracteres, na linha imediatamente anterior à
> linha corrente; no caso "BBB".
> É isso.
Esta parte está ok, apenas muito complexa.

> Se eu tiver entendido a coisa errado, se houver ideias complementares; ou se
> houver uma forma melhor de fazer isso, por favor sintam-se livres para
> responder.
Você pode resumir para:

$ sed '/^AAA$/{n;s/^EEE$/BBB\nCCC\nDDD\n&/}' teste

Para facilitar a visualização do resultado final para este caso, pode-se
usar, por exemplo, um diff -y:

$ diff -y teste <(sed '/^AAA$/{n;s/^EEE$/BBB\nCCC\nDDD\n&/}' teste)

ou ainda trocar o 'diff -y' por 'vimdiff'.

> Grande abraço,
> Rodrigo Boechat

[]'s
--
"Não manejo bem as palavras
Mas manipulo bem as strings."
------------------------------
http://tecnoveneno.blogspot.com



reply via email to

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