Extract XML Value in bash script [duplicate] Extract XML Value in bash script [duplicate] bash bash

Extract XML Value in bash script [duplicate]


As Charles Duffey has stated, XML parsers are best parsed with a proper XML parsing tools. For one time job the following should work.

grep -oPm1 "(?<=<title>)[^<]+"

Test:

$ echo "$data"<item>   <title>15:54:57 - George:</title>  <description>Diane DeConn? You saw Diane DeConn!</description> </item> <item>   <title>15:55:17 - Jerry:</title>   <description>Something huh?</description>$ title=$(grep -oPm1 "(?<=<title>)[^<]+" <<< "$data")$ echo "$title"15:54:57 - George:


XMLStarlet or another XPath engine is the correct tool for this job.

For instance, with data.xml containing the following:

<root>  <item>     <title>15:54:57 - George:</title>    <description>Diane DeConn? You saw Diane DeConn!</description>   </item>   <item>     <title>15:55:17 - Jerry:</title>     <description>Something huh?</description>  </item></root>

...you can extract only the first title with the following:

xmlstarlet sel -t -m '//title[1]' -v . -n <data.xml

Trying to use sed for this job is troublesome. For instance, the regex-based approaches won't work if the title has attributes; won't handle CDATA sections; won't correctly recognize namespace mappings; can't determine whether a portion of the XML documented is commented out; won't unescape attribute references (such as changing Brewster & Jobs to Brewster & Jobs), and so forth.


I agree with Charles Duffy that a proper XML parser is the right way to go.

But as to what's wrong with your sed command (or did you do it on purpose?).

  • $data was not quoted, so $data is subject to shell's word splitting, filename expansion among other things. One of the consequences being that the spacing in the XML snippet is not preserved.

So given your specific XML structure, this modified sed command should work

title=$(sed -ne '/title/{s/.*<title>\(.*\)<\/title>.*/\1/p;q;}' <<< "$data")

Basically for the line that contains title, extract the text between the tags, then quit (so you don't extract the 2nd <title>)