1

I have below command to find all the .xml files containing the <active>true</active> having <codePool>community</codePool> after that line on next line.

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

Now how to combine this with sed to replace true string inside the <active>... tag to false string along those matched lines ?

3
  • Watch out, you might get an answer from this guy: stackoverflow.com/a/1732454/5851520 :-)
    – SusanW
    Nov 10, 2016 at 11:22
  • ... which is why you have the -z in there. Good, good...
    – SusanW
    Nov 10, 2016 at 11:49
  • Question: that grep will detect files where the codePool/community thing is anywhere in the file after the active bit. Is that ok? You say "on the next line", but the grep isn't caring about that.
    – SusanW
    Nov 10, 2016 at 11:57

2 Answers 2

2

You should use XML parsing tools for XML data. xmlstarlet is a good choice. Regular expressions are just not powerful enough (canonical reference)

If your data looks like:

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

Then

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

produces

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

Here's an awk program that does what you request. Keep in mind that it's fragile: if the input changes, this code will stop working. It does just use plain string operations.

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}
'
2
  • That canonical reference needs updating for XHTML->"XML generally". I fear the original author was eaten by Tony the Pony.
    – SusanW
    Nov 10, 2016 at 15:06
  • @glennjackman, Your answer is quite well, but I am working on Remote SSH that is owned by client, so I don't have permission to install any third party software/library into his system. Please suggest also a ubuntu or any well-known linux command line alternative to this.
    – Vicky Dev
    Nov 10, 2016 at 15:17
0

Thanks for the answer @glennjackman, I was also successfull achieving my requirement with the following code, it is vulnerable in-case the input changes, but it will be consistent keeping the fixed directory structure and file format of xml files of Magento, in mind:

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

This way I was also able to backup those files first, that were going to be modified, just the way I wanted.

Hope this simplifies things and redirects all/as many as possible people to using domestic libraries rather than installing third party tools which aren't allowed to install on Remote SSH/VPN networks.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .