O processamento de XML como texto geralmente não é uma solução robusta, mas se você insistir em fazê-lo, talvez possa usar o espaço de armazenamento do sed , por exemplo
sed -e '/<id>[0-9]*<\/id>/h' -e '/<root>/{x;p;x;}' file.xml
Eu tenho um arquivo XML que se parece com isso:
<id>456</id>
<root>
<value>1</value>
<intNum>2</intNum>
</root>
<root>
<eulav>1</eulav>
<muNtni>2</muNtni>
</root>
Eu quero lembrar de <id>456</id> e fazer isso:
sed 's/\<root\>/\
\<root\>
$herecomestheid
Basicamente, o que isto faz é substituir <root> por <root>\n<id>456</id> . \n neste caso significa nova linha. Eu já sei disso, mas o problema que estou tendo é lembrar <id>456</id> e mantê-lo pronto para uso posterior.
Eu tentei isso (o que obviamente não funcionou):
sed -i '' 's/\<root\>/\
\<root\>\
\<id\>.\<\/id\>/g'
e eu tentei fazer algo assim:
cat file.xml | grep '\<id\>*\<\/id\>'
E tentei transformar a saída grep em uma variável. E isso obviamente não funcionou também.
EDIT: <id>*</id> está supostamente na raiz.
sed -e :b -e '$!{N;\|<id>.*\n<root>|!bb
};do what ever you want to do with all of those lines now....'
Concordo com a steeldriver que h oldspace é provavelmente a melhor aposta, mas há outras opções. Às vezes, não podemos nos incomodar em gerenciar os dois buffers - ou, como geralmente é problema meu - já estamos gerenciando os dois buffers. O trecho acima empilha linhas no espaço padrão. Contanto que sempre ocorra entre <id> tags, ele preencherá recursivamente o espaço padrão com o bloco de dados desejado antes de prosseguir para a linha 2 - isto é, ele fará isso enquanto os buffers não implodem enquanto isso - mas isso é algo difícil de fazer hoje em dia .
Além disso, voltando à parte do h old space, e x change realmente troca h old e space space. Usá-lo uma vez renderiza o buffer padrão como o buffer h old e vice-versa. Este efeito sobrevive aos ciclos de linha. Muitas vezes, o que eu faço é ler um arquivo até chegar a uma linha inicial, realizar edições preliminares, depois trocar e manter H olding até obter outra. Quando meu script troca de volta, acaba em um bloco atrás - no último marcador que eu liguei, além de tudo, H eld enquanto isso. É uma maneira simples de armazenar apenas o máximo que for necessário.
E assim, outra maneira de implementar um loop como você deseja fazer é:
sed -e '/<id>/h;//!H;/<root>/!{$!d' -e '};x...'
A partir desse ponto, seu espaço de padrão é H old space e vice-versa. h old irá sobrescrever h espaço antigo com o espaço padrão atual sempre que for usado - então o exemplo acima inicia um novo buffer com uma linha <id> todas as vezes. !H acrescenta todas as linhas intermediárias a H old space, cada uma seguindo um caractere \n ewline. $!d elimina o espaço padrão em cada linha que é ! , não a $ última, quando a linha atual estiver com segurança H eld e inicia o próximo ciclo de linha e, portanto, a alteração x ocorre apenas em <root> corresponde ao momento em que o bloco inteiro está esperando por você.
Lembre-se apenas que, no seu bloco último , o marcador é provavelmente a última linha, caso seja diferente das correspondências <root> .
Mas ...
De acordo com sua edição, não vejo nenhum motivo pelo qual você não possa se safar:
sed '/<id>/h;//d;\|</root>|G
' <<\INPUT
unimportant 1
<id> number 1 </id>
<root> sub text
more text
more text
</root>
<root> sub text as well
and more text
and more text
</root>
unimportant 2
<id> number 2 </id>
<root> sub text
more text
more text
</root>
<root> sub text
and more text
and more text
</root>
INPUT
Há <id> linhas são h eld (novamente: sobrescrevendo h espaço antigo) e, em seguida, d da saída. Quando ocorre uma coincidência </root> , sed G define o espaço h old anexado ao espaço padrão antes de imprimir automaticamente os resultados no final do ciclo de linha, que se parece com:
unimportant 1
<root> sub text
more text
more text
</root>
<id> number 1 </id>
<root> sub text as well
and more text
and more text
</root>
<id> number 1 </id>
unimportant 2
<root> sub text
more text
more text
</root>
<id> number 2 </id>
<root> sub text
and more text
and more text
</root>
<id> number 2 </id>
Uma solução usando awk seria
awk '/<id>/{id=$0}/<root>/{print id}1' file.xml
Se você não quiser imprimir a linha <id> , pule essa linha adicionando next .
awk '/<id>/{id=$0;next}/<root>/{print id}1' file.xml
Tags bash grep text-processing sed