I am having difficulty getting sed to replace a string of text in an XML file, despite the fact that I have no trouble using grep to find that same string. Since the new string and old string to be replaced contain a lot of special characters, I thought it best to store them in variables as opposed to using a slew of backslashes:

OLD_STRING='<property name="webServiceHost">${jboss.bind.address}</property>'
NEW_STRING='<!--<property name="webServiceHost">${jboss.bind.address}</property>-->'

The strings appear to be stored as expected:

$ echo $OLD_STRING; echo $NEW_STRING
<property name="webServiceHost">${jboss.bind.address}</property>
<!--<property name="webServiceHost">${jboss.bind.address}</property>-->

Grep'ing confirms the old string is present in the XML file:

$ grep "$OLD_STRING" jboss-beans.xml
<property name="webServiceHost">${jboss.bind.address}</property>

But the following sed command produces no output whatsoever:

sed -i 's/"$OLD_STRING"/"$NEW_STRING"/g' jboss-beans.xml

Any idea what I'm missing here?


Putting shell variables in single quotes disables their interpretation. That's why your command has no effect.

$ echo  's/"$OLD_STRING"/"$NEW_STRING"/g'

It should be written like that:

sed -i "s/'$OLD_STRING'/'$NEW_STRING'/g" jboss-beans.xml

But then the variables are interpreted before calling sed and the again contain special characters:

$ echo  "s/'$OLD_STRING'/'$NEW_STRING'/g"
s/'<property name="webServiceHost">${jboss.bind.address}</property>'/'<!--<property name="webServiceHost">${jboss.bind.address}</property>-->'/g

For that reason sed has this special featur allowing to define the s/// command delimiters by simply using them, e.g.:

sed -i "s#'$OLD_STRING'#'$NEW_STRING'#g" jboss-beans.xml

Still your search expression contains special regexp characters, and using sed like this is just waste of its abilities. I would write the expression like this:

sed -i 's/\(<.*webServiceHost.*jboss.bind.address.*>\)/<!--\1-->/' jboss-beans.xml

Of course you can make the match string more or less specific according to your needs. There is also other nice feature that can help. sed allows to narrow editing operations to the lines matching a specific pattern. Your command could look like this:

sed -i '/webServiceHost/ s/^\(.*\)$/<!--\1-->/' jboss-beans.xml
  • Ah yes, I had totally forgotten about using \1 to keep part of the pattern in regular expressions and/or sed. Thanks! Unfortunately, there still seems to be a bit of misinterpretation going on: $ sed -i 's|(<.*webServiceHost.*jboss.bind.address.*>)|<!--\1-->|' jboss-beans.xml: -e expression #1, char 55: invalid reference \1 on s' command's RHS I also tried adding backslashes before both parentheses, but again I get no output. – rolinrok May 2 '11 at 19:39
  • @rolinrok Yes, my mistake. I've forgotten about backslashes before parentheses. As for the 'no output issue' it would help if you put the part of the XML file you want to comment out with some lines before and after it. My examples assume that your properties are alone in a line so the whole line is commented out, but that might be wrong assumption. – Rajish May 2 '11 at 22:50
  • Got it! Was expecting to see the change on standard output during testing, but forgot I was using the -i option. After checking the file, I noticed multiple commenting characters around the desired string. Thanks again! – rolinrok May 3 '11 at 4:52
  • @rolinrok Glad I could help you. Would be nice if you accepted the answer ;) – Rajish May 3 '11 at 20:34
  • Done! Sorry for the delay -- Still a superuser noob and only just now realized I forgot to accept your answer :) – rolinrok Aug 16 '11 at 20:41

This may be useful for you:
Commandline XML manipulation

apt-get install xmlstarlet

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.