JSON array to bash variables using jq
Your original version isn't going to be eval
able 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 eval
able 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.
Building on @Michael Homer's answer, you can avoid a potentially-unsafe eval
entirely by reading the data into an associative array.
For example, if your JSON data is in a file called file.json
:
#!/bin/bash
typeset -A myarray
while IFS== read -r key value; do
myarray["$key"]="$value"
done < <(jq -r '.SITE_DATA | to_entries | .[] | .key + "=" + .value ' file.json)
# show the array definition
typeset -p myarray
# make use of the array variables
echo "URL = '${myarray[URL]}'"
echo "CREATED = '${myarray[CREATED]}'"
echo "AUTHOR = '${myarray[URL]}'"
Output:
$ ./read-into-array.sh
declare -A myarray=([CREATED]="10/22/2017" [AUTHOR]="John Doe" [URL]="example.com" )
URL = 'example.com'
CREATED = '10/22/2017'
AUTHOR = 'example.com'