Grep substitui em vários arquivos xml

1

Eu tenho o comando abaixo para encontrar todos os arquivos .xml contendo o <active>true</active> com <codePool>community</codePool> depois da linha na próxima linha.

grep -rzl '<active>true</active>.*<codePool>community</codePool>' --include='*.xml' --color=always

Agora, como combinar isso com sed para substituir true string dentro da tag <active>... para false string nas linhas correspondentes?

    
por Vicky Dev 10.11.2016 / 11:52

2 respostas

0

Obrigado pela resposta @glennjackman, eu também fui bem sucedido em alcançar minha exigência com o seguinte código, é vulnerável no caso de a entrada mudar, mas será consistente manter a estrutura de diretório fixa e o formato de arquivo de arquivos xml do Magento em mente:

for filename in *.xml; do
    if grep -q '<codePool>community</codePool>' "$filename"; then
        if [[ $filename != *"Mage_"* ]]; then
            sed -i.bak 's/<active>true<\/active>/<active>false<\/active>/g' "$filename"
        fi
    fi
done

Dessa forma, também consegui fazer o backup desses arquivos primeiro, que seriam modificados da maneira que eu queria.

Espero que isso simplifique as coisas e redirecione todas as pessoas possíveis para o uso de bibliotecas domésticas, em vez de instalar ferramentas de terceiros que não podem ser instaladas em redes SSH / VPN remotas.

    
por Vicky Dev 10.11.2016 / 20:50
2

Você deve usar ferramentas de análise XML para dados XML. xmlstarlet é uma boa escolha. Expressões regulares não são poderosas o suficiente ( referência canônica )

Se seus dados se parecem com:

<root>
  <foo>
    <active>true</active>
    <codePool>private</codePool>
  </foo>
  <foo>
    <active>true</active>
    <codePool>community</codePool>
  </foo>
</root>

Então

xmlstarlet ed --update '//active[.="true" and ../codePool="community"]' -v false file.xml

produz

<?xml version="1.0"?>
<root>
  <foo>
    <active>true</active>
    <codePool>private</codePool>
  </foo>
  <foo>
    <active>false</active>
    <codePool>community</codePool>
  </foo>
</root>

Aqui está um programa awk que faz o que você pede. Tenha em mente que é frágil: se a entrada for alterada, esse código deixará de funcionar. Ele apenas usa operações de string simples.

awk '
    BEGIN {
        marker = "<codePool>community</codePool>"
        srch = "<active>true</active>"
        repl = "<active>false</active>"
    }
    index($0, marker) {
        i = index(prev, srch)
        if (i > 0) 
            prev = substr(prev, 1, i-1) repl substr(prev, i+length(srch))
    }
    {
        if (prev) print prev
        prev = $0
    }
    END {if (prev) print prev}
'
    
por glenn jackman 10.11.2016 / 14:56