Search code examples
xmlbashxpathxmlstarlet

refer to bash variable or bash expression in xmlstarlet (xpath) expression


I want to match a date in an xml attribute. I've tried the following command:

xmlstarlet sel -t -v 'string(//*[local-name()="***"][@date="$(date +'%d %b %y')"]/@...)' file.xml

I've also tried to replace the bash expression with a bash variable. I've used single and double quotes, normal and curly parentheses, and no dice.


Solution

  • You need to close your single quotes before opening double quotes; otherwise, the single-quotes quote the double quotes, so they have no effect.

    xmlstarlet sel -t -v \
      'string(//*[local-name()="***"][@date="'"$(date +'%b %d $y')"'"]/@...)' file.xml
    
    # 'single-quoted content here"'"double-quoted content here"'"single-quoted content here'
    # |                          ^|                            |^                          |
    # |||||||||||||||||||||||||||||                            |||||||||||||||||||||||||||||
    

    The "s with ^ characters under them as LITERAL: They're escaped by the single-quotes surrounding them, and thus become part of the string passed to xmlstarlet. The other ", not surrounded by ', are syntactic: They're directives to the shell that contents of the $(date) expansion are not to be word-split or glob-expanded. (The pipes are showing which parts of the string are single-quoted, with the caveat that the single-quotes on the end are syntactic rather than literal, and thus not actually quoted themselves).

    It may be easier to look at the differently-quoted substrings the shell is concatenating into a single argument-list element:

    • 'string(//*[local-name()="***"][@date="' - Single-quoted, including the literal " at the end.
    • "$(date +'%b %d $y')" - Double-quoted.
    • '"]/@...)' - Single-quoted, including the literal " at the beginning.