procura e substitui em sed com padrão multilinha

2

Eu tenho um arquivo cujo conteúdo é o seguinte:

alfa
[many lines here]
TAG1
TAG2

bravo
TAG3

charlie
TAG4
[many lines here]

onde TAG1, TAG2, TAG3 e TAG4 são sequências fixas e alfa, bravo e charlie mudam de tempos em tempos e eu quero extrair:

alfa-bravo-charlie

Qual é o comando preciso do sed que tenho que usar? Eu não sei como trabalhar com o padrão de várias linhas. : (

P.S .: estou usando sed para windows.

    
por Toc 14.12.2009 / 14:20

2 respostas

3

Isso funciona com o gnu sed, eu não acho que ele dependa de extensões específicas do gnu, mas eu não sei.

echo "$yourdata" | sed -ne '1{h;d}; /^TAG1$/ {n; /^TAG2$/{n;N;N; /\nTAG3$/ {s///; H; n;N;N; /\nTAG4$/ {s///; H; g; s/\n\n/-/gp; q; } } } }'

Resultado: alfa-bravo-charlie

Como isso funciona? Primeiro dizemos ao sed "-n" que queremos que não imprima nada, a menos que digamos especificamente [p] rint.

O primeiro bloco da expressão sed é "1 {h; d}". Isto diz que quando lemos a linha 1, stash essa linha no buffer [h] antigo, em seguida, [d] excluí-lo do buffer de trabalho para que possamos ler a próxima linha e passá-lo através da expressão sed desde o início. p>

Ao ler linhas subseqüentes, o bloco "1 {...}" será ignorado.

Não combinamos mais até chegarmos à linha TAG1. Neste ponto, nós executamos o longo {...} bloco. Isto diz primeiro ler a linha [n] ext, sobrescrevendo a linha TAG1 que estava no buffer. Se o buffer agora é TAG2, então nós executamos o próximo bloco {...} interno. Isso primeiro lê a linha [n] ext, sobrescrevendo o que já está no buffer. Os próximos dois comandos são "N; N". Isso significa ler as próximas 2 linhas, mas anexá-las ao buffer de trabalho, em vez de sobrescrevê-lo. Se o buffer de trabalho agora corresponde a / \ nTAG3 $ /, então executamos o próximo bloco {...} interno. Isso diz primeiro "s ///", em outras palavras, substitui a string vazia pela expressão mais correspondida recentemente. Isso exclui o "\ nTAG3" do final do buffer de trabalho, deixando "\ nbravo". Então fazemos [H], que acrescenta isso ao buffer de espera. ([h] sobrescreve o buffer de retenção, [H] anexa a ele). Então agora o buffer de espera contém a primeira linha "alfa", depois a próxima linha "\ nbravo". Estes são unidos por uma nova linha, então nós realmente temos "alfa \ n \ nbravo". Nós cuidaremos das duas novas linhas mais tarde.

Continuamos até obter "alfa \ n \ nbravo \ n \ ncharly" no buffer de armazenamento. Em seguida, dizemos [g] et o buffer de espera (sobrescrevendo o que está no buffer de trabalho). Fazemos um "s / \ n \ n / - /" para transformar as novas linhas duplas em traços. Adicionamos sinalizadores "g" e "p" ao final do comando [s] para que a substituição funcione globalmente (isto é, não faça apenas uma substituição e pare) e que o resultado após a substituição seja [r]. / p>

Então, nós [q] uit, não precisamos ler o restante do fluxo de entrada.

    
por 14.02.2010 / 01:15
1

Não está claro no seu exemplo exatamente o que você está tentando fazer. Parece que você está tentando descartar todo o conteúdo do arquivo, além de um conjunto de três marcadores, que você deseja unir. Você não precisa de sed para isso, basta digitar:

echo alfa-bravo-charlie

E você realizou seu objetivo. Se você simplesmente deseja remover o conteúdo entre "alfa" e "charlie", você pode usar um script sed como este:

/charlie/ a\
alfa-bravo-charlie
/alfa/,/charlie/ d

Se isso não é o que você quer fazer, pode ajudar se você esclarecer o seu exemplo.

    
por 14.12.2009 / 15:37