I have tried grep, awk, sed and am starting to try xmlstarlet but I'm not finding much support with that.

I'm guessing the xmlstarlet is telling me that the XML is ill formed, but all I want to do is find tags that contain a specific hex color and print the text between the tags.

My file.xml looks like this:

<p style=" margin-left: 80.0px;">Do not print this.</p>
<p style=" margin-left: 80.0px;"><span style=" color: #595959;">Print this.</span></p>

I have tried

$ cat file.xml | grep -oP '(?<=\"<span style="color: #595959;">\").*?(?=\"</span>")'

grep produces no output

sed -n '/span style=" color: #595959/,/<\/span/p'  file.xml

sed returns the entire line and continues to print every line afterwards in the xml file, but I only want the text between the tags.

awk -F "[><]" '/span style=" color: #595959;"’/{print $3} file.xml

awk command runs but does not terminate or print anything.

xmlstarlet produces:

Unescaped '<' not allowed in attributes values

which is referring to another line in the file, but I am guessing this violation is why xmlstarlet halts.


Considering that the file.xml is not properly formatted xml, you can do the following:

grep -o '<span style=\" color: #595959;">.*</span>' file.xml | xmllint --xpath 'string(//span)' -

The grep part of the command will find the whole line containing your desired span tag (tags included). The line is then piped to xmllint that will use xpath query to locate your text. Keep in mind that this will work if you do not have multiple span tags, that match the grep criteria, in the same line.

However, if you have properly formed xml, you can use only xmllint (I just put and tags around your file), which is preffered way to work with xml files. The command would be:

xmllint --xpath 'string((//span[@style=" color: #595959;"])[1])' file.xml

Note the [1] in the command. This is used to show you the first result of the query. If you have multiple span tags with same style attribute, you can get those texts by using [2], [3], etc.

  • Thanks for answering. I stopped checking back here after a while as right around the time you answered, I found a lead. I realized that all I needed to do was to grep for the hex color and not worry about any other part of the line. That would print whole lines containing one or more words of that color and eventually i found a way to strip away the tags to leave just the text by piping to awk. grep 595959 | awk -F: '{if(f!=$1)print ""; f=$1; print $0;}' I have not tried your way yet, but thanks again.
    – Insideup
    Sep 4 '20 at 22:34
  • Update: I'm using sed -e 's/<[^>]*>//g' to remove the tags, but its also removing text in quotes. And the whole script is not catching all matches.
    – Insideup
    Sep 7 '20 at 15:15

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.