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.