#begin command block
#append all lines between two addresses to hold space
sed -n -f - <<\SCRIPT file.xml
\|<tag1>|,\|</tag1>|{ H
#at last line of search block exchange hold and pattern space
\|</tag1>|{ x
#if not conditional ; clear buffer ; branch to script end
\|<tag2>[^<]*foo[^\n]*</tag2>|!{s/.*//;h;b}
#do work ; print result; clear buffer ; close blocks
s?*?*?;p;s/.*//;h;b}}
SCRIPT
Se você fizer o acima, com os dados exibidos, antes da última linha de limpeza, deverá trabalhar com um sed
espaço padrão que se parece com:
^\n<tag1>\n<tag2>foo</tag2>\n</tag1>$
Você pode imprimir seu espaço padrão sempre que quiser com l
ook. Você pode endereçar os \n
caracteres.
sed l <file
Mostrará a você que cada linha a sed
processa no estágio em que l
é chamada.
Então, eu apenas testei e precisava de mais um \backslash
após o ,comma
na primeira linha, mas, caso contrário, funciona como está. Aqui eu o coloco _sed_function
para que eu possa chamá-lo facilmente para fins de demonstração ao longo desta resposta: (funciona com comentários incluídos, mas são removidos aqui por uma questão de brevidade)
_sed_function() { sed -n -f /dev/fd/3
} 3<<\SCRIPT <<\FILE
\|<tag1>|,\|</tag1>|{ H
\|</tag1>|{ x
\|<tag2>[^<]*foo[^\n]*</tag2>|!{s/.*//;h;b}
s?*?*?;p;s/.*//;h;b}}
#END
SCRIPT
<tag1>
<tag2>bar</tag2>
</tag1>
<tag1>
<tag2>foo</tag2>
</tag1>
FILE
_sed_function
#OUTPUT#
<tag1>
<tag2>foo</tag2>
</tag1>
Agora vamos mudar p
para um l
para que possamos ver com o que estamos trabalhando enquanto desenvolvemos nosso script e removemos a demonstração não operacional, s?
para que a última linha do nosso se sed 3<<\SCRIPT
pareça com:
l;s/.*//;h;b}}
Então eu vou executá-lo novamente:
_sed_function
#OUTPUT#
\n<tag1>\n <tag2>foo</tag2>\n</tag1>$
Está bem! Então, eu estava certa - é um sentimento bom. Agora, vamos embaralhar nosso l
redor para ver as linhas que ele puxa, mas exclui. Removeremos nossa atual l
e adicionaremos uma à !{block}
que se parece com:
!{l;s/.*//;h;b}
_sed_function
#OUTPUT#
\n<tag1>\n <tag2>bar</tag2>\n</tag1>$
É assim que parece antes de acabarmos.
Uma última coisa que quero mostrar é o H
antigo espaço à medida que o construímos. Espero que possa demonstrar alguns conceitos-chave. Então, removo o último l
OK novamente e altero a primeira linha para adicionar uma espiada no H
espaço antigo no final:
{ H ; x ; l ; x
_sed_function
#OUTPUT#
\n<tag1>$
\n<tag1>\n <tag2>bar</tag2>$
\n<tag1>\n <tag2>bar</tag2>\n</tag1>$
\n<tag1>$
\n<tag1>\n <tag2>foo</tag2>$
\n<tag1>\n <tag2>foo</tag2>\n</tag1>$
H
o espaço antigo sobrevive aos ciclos de linha - daí o nome. Então, o que as pessoas geralmente tropeçam - ok, o que eu tropeço frequentemente - é que ele precisa ser excluído depois que você o usa. Nesse caso, eu apenas x
troco uma vez, para que o espaço de espera se torne o espaço padrão e vice-versa, e essa mudança também sobrevive aos ciclos de linha.
O efeito é que eu preciso excluir meu espaço de espera, que costumava ser meu espaço de padrão. Eu faço isso limpando primeiro o espaço do padrão atual com:
s/.*//
O que simplesmente seleciona todos os personagens e os remove. Não posso usá-lo d
porque isso encerraria meu ciclo de linha atual e o próximo comando não seria concluído, o que seria um lixo para o meu script.
h
Isso funciona de maneira semelhante a, H
mas substitui o espaço de espera, então eu apenas copiei meu espaço de padrão em branco por cima do meu espaço de espera, excluindo-o efetivamente. Agora eu posso apenas:
b
Fora.
E é assim que escrevo sed
scripts.