0

I'm bashing my head against the wall with this one. How do I do a regex replacement with sed on text that contains a newline?

I need to replace the value of the "version" XML element shown below. There are multiple version elements so I want to replace the one that comes after the "name" element.

<name>MyName</name>
<version>old</version>

Here's my command:

sed -i -E "s@(\s*<name>$NAME</name>\n\s*<version>)$VERSION_OLD(</version>)@\1$VERSION_NEW\2@g" $myfile.txt

Now as far as I know there is a way to make sed work with a newline character, but I can't figure it out. I've already used sed in my script so ideally I'd prefer to re-use it instead of say perl.

Tom Zych
  • 13,329
  • 9
  • 36
  • 53
Boon
  • 1,073
  • 1
  • 16
  • 42
  • 2
    The solution is to use a tool designed for working with XML, not sed! – Tom Fenech Nov 11 '15 at 17:07
  • Is there a decent standard Bash tool for parsing and manipulating XML? This is part of a larger Bash script... – Boon Nov 11 '15 at 17:09
  • Regarding parsing XML with regex, see [the famous post](http://stackoverflow.com/a/1732454/675568). – Tom Zych Nov 11 '15 at 17:21
  • I'm not aware of any tool that would provide you with a one-line solution - perhaps it's worth looking at a solution in a language such as perl or python. Alternatively there's always good ol' XSLT :) – Tom Fenech Nov 11 '15 at 17:26

2 Answers2

3

When you see your name element, you will need to use the N command to read the next line:

file:

<bar>MyName</bar>
<version>old</version>
<name>MyName</name>
<version>old</version>
<foo>MyName</foo>
<version>old</version>

With GNU sed:

sed '/<name>/{N;s/old/newer/}' file

Output:

<bar>MyName</bar>
<version>old</version>
<name>MyName</name>
<version>new</version>
<foo>MyName</foo>
<version>old</version>
Toby Speight
  • 27,591
  • 48
  • 66
  • 103
Cyrus
  • 84,225
  • 14
  • 89
  • 153
0

If you're using GNU sed, you can use its extended addressing syntax:

sed '/<name>/,+1{/<version>/s/old/newer/}' file

Breaking this down, it says: for a line matching <name> and the following line (+1), then if the line matches <version>, substitute old with newer.

I'm assuming here that your file is generated, and will always have the name and version elements each on a single line, and adjacent. If you need to handle more free-form XML, then you should really consider an XPath-based tool rather than sed.

Toby Speight
  • 27,591
  • 48
  • 66
  • 103