Search code examples
argumentscommand-line-interfacejq

Using jq, how do I substitute a variable within a string?


When given a string in JSON where I'd like only a part of it templated/substituted:

{
  "title": "Where the $color Fern Grows"
}

Trying to template that with jq args doesn't seem to work:

cat example.json | jq --arg color "Red"

jq doesn't like the substitution and returns the un-templated example.json with $color in the output

How can you tell jq to replace variables mid JSON string?

Thanks.

Solution:

The issue seems to be that jq assumes data on stdin is formatted JSON data. This substitution actually only works on a "filter", which is jq's term for a script. Using the flags -n and -f [filter.json] to correctly state the input data is a filter, not actual data and using the \($var) syntax, as @peak pointed out works well.

example.json then could become example.jq:

{
  "title": "Where the \($color) Fern Grows"
}

Which when run, as they suggested:

jq -n --arg color "Red" -f example.jq

Works perfectly. The concept between data and filter is important and one I didn't realize. I thought it was all just interpolation and templating like most other programs. This seems to take more inspiration from awk where this is common however.


Solution

  • For suggested ways to use jq as a template engine, see the jq Cookbook: https://github.com/stedolan/jq/wiki/Cookbook#using-jq-as-a-template-engine

    In your case, it would probably be better to use the "interpolation" approach as per your original SO question: jq not replacing json value with parameter

    example.jq:

    {
      "title": "Where the \($color) Fern Grows"
    }
    

    Invocation:

    jq -n --arg color Red -f example.jq
    

    or:

    jq --arg color Red . <(example.jq)
    

    Otherwise ...

    ... you could use sub, though that might be brittle.