Convert JSON Array to Bash Variables Using jq – Tutorial

bashjq

I've got a JSON array like so:

{
  "SITE_DATA": {
    "URL": "example.com",
    "AUTHOR": "John Doe",
    "CREATED": "10/22/2017"
  }
}

I'm looking to iterate over this array using jq so I can set the key of each item as the variable name and the value as it's value.

Example:

  • URL="example.com"
  • AUTHOR="John Doe"
  • CREATED="10/22/2017"

What I've got so far iterates over the array but creates a string:

constants=$(cat ${1} | jq '.SITE_DATA' | jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]")

Which outputs:

URL=example.com
AUTHOR=John Doe
CREATED=10/22/2017

I am looking to use these variables further down in the script:

echo ${URL}

But this echos an empty output at the moment. I'm guessing I need an eval or something in there but can't seem to put my finger on it.

Best Answer

Your original version isn't going to be evalable because the author name has spaces in it - it would be interpreted as running a command Doe with the environment variable AUTHOR set to John. There's also virtually never a need to pipe jq to itself - the internal piping & dataflow can connect different filters together.

You can make a much simpler version of the jq program:

jq -r '.SITE_DATA | to_entries | .[] | .key + "=\"" + .value + "\""'

which outputs:

URL="example.com"
AUTHOR="John Doe"
CREATED="10/22/2017"

There's no need for a map: .[] deals with taking each object in the array through the rest of the pipeline as a separate item, so everything after the last | is applied to each one separately. At the end, we just assemble a valid shell assignment string with ordinary + concatenation, including quotes around the value.

All the pipes matter here - without them you get fairly unhelpful error messages, where parts of the program are evaluated in subtly different contexts.

This string is evalable as long as the characters `, $, newline and null don't appear in the data:

eval "$(jq -r '.SITE_DATA | to_entries | .[] | .key + "=\"" + .value + "\""' < data.json)"
echo "$AUTHOR"

As ever when using eval, be careful that you trust the data you're getting, since if it's malicious or just in an unexpected format things could go very wrong.

Related Question