Isso pode funcionar para você (GNU sed?):
sed '/^\s*<tree.*\<bar="/!b;s//&\n/;:a;s/\n\([^c"]\+\)/\n/;ta;s/\nc/X\n/;ta;:b;s/\n//' XML
Eu quero mudar caracteres em um arquivo XML usando sed. A entrada é assim:
<!-- Input -->
<root>
<tree foo="abcd" bar="abccdcd" />
<dontTouch foo="asd" bar="abc" />
</root>
Agora, quero alterar todos os c para X na tag de barra do elemento da árvore.
<!-- Output -->
<root>
<tree foo="abcd" bar="abXXdXd" />
<dontTouch foo="asd" bar="abc" />
</root>
Como está o comando sed correto? Por favor, considere, pode haver mais de uma ocorrência de c (um ao lado do outro ou não) em uma tag ...
Eu tentei isso sozinho, mas ele não vai alterar vários c, e ele adiciona um X: (
sed -i 's/\(<tree.*bar=\".*\)c\(.*\"\/>\)/X/g' Input.xml
Editar: mais alguns detalhes;)
Este é um trabalho único, depois que o documento é alterado, nunca mais vou tocá-lo
A estrutura é tão fácil quanto acima. Isso significa que eu posso pegar todas as linhas (isso funciona) com:
cat input.xml | grep ""
Então, supondo que eu tenha a string correta extraída, e saiba onde escrevê-la após a modificação: Como alterar 'abcdeccd' para 'abXdeXXd'? Este não é realmente um problema XML, mas um regex, ou estou errado aqui?
Como a RedGrittyBrick disse, a melhor maneira de fazer isso é usar um analisador XML, escolhendo o elemento, traduzindo os caracteres e, em seguida, escrevê-lo de volta usando uma biblioteca XML. Isso não lhe dará surpresas desagradáveis, resistirá ao teste do tempo, etc. Não é apenas o melhor, é muito superior a outras coisas. Outras soluções mais ou menos instantaneamente se tornam pesadelos para depurar, e certamente haverá problemas ocultos mais ou menos em qualquer lugar.
Se é apenas uma tarefa simples que precisa ser feita uma vez, e uma é muito cuidadosa, e uma verifica o resultado, etc., etc., etc., então pode ser menos trabalho fazer isso do jeito ruim. Mas vai surpreendê-lo algum dia se você fizer disso um hábito.
Como exemplo, aqui está uma das formas ruins que parecem funcionar, mas não se baseia apenas no XML válido , mas na sintaxe mais ou menos exata que você descreveu anteriormente, que é apenas um subconjunto de XML válido, e assim XML válido é certamente capaz de fazer o código falhar (e se alguém adicionar um sinal '>' em uma das tags? Adicione um especial E se alguém não usar aspas? Adicione um caso especial e assim por diante). Este é o problema de não usar um parser real. Alguns cuidados foram tomados abaixo para agir como um pseudoparser, pelo menos, lendo a tag, então agindo sobre ela, depois escrevendo de volta, mas existem ferramentas prontas para isso que foram testadas extensivamente.
#!/bin/sh
IFS='\n'
while read i; do
if $(printf -- "${i}" | grep -qE '<tree [^>]+ bar="[^'"${1}"'"]*'"${1}"); then
ORIGTAG=$(printf -- "${i}" | sed 's#^.*<tree [^>]\+ bar="\([^"]\+\)".*$##g')
NEWTAG=$(printf -- "${ORIGTAG}" | tr "${1}" "${2}")
printf -- "${i}\n" | sed 's#\(^.*<tree [^>]\+ bar="\)'"${ORIGTAG}"'\(".*$\)#'"${NEWTAG}"'#g'
else
printf -- "${i}\n"
fi
done < "${3}"
Uso: script.sh [caractere a substituir] [substituindo caractere] [nome do arquivo], por exemplo
script.sh c X myfile
IFS
define o "separador de campo interno" no shell para nova linha, para manter os espaços em branco no início das linhas.
while read
lê o arquivo de entrada (dado como argumento 3 para o script) linha por linha.
grep
verifica se a tag específica está na linha atual E se a tag contém o caractere a ser traduzido. Se sim, vá para sed
logic; se não, retorne a linha como está.
sed
seleciona a tag antiga, executa uma tradução de caractere e retorna a linha com a nova tag.
Como você pode ver, ninguém gostaria de encontrar este script e ter que depurá-lo. Se isso é qualquer coisa mais do que um trabalho único, não faça assim. Para a sanidade de futuros observadores.