dominictarr/JSON.sh

return as environment variable

Opened this issue · 5 comments

i use JSON.sh as curl 'http://conf.com/conf/config_20150920_test.json' | ./JSON.sh -l -p -b -s and it work greet and it return result like

["storage","mysql","u_db","database"]   "dev"
["storage","mysql","u_db","username"]   "user"
["storage","mysql","u_db","password"]   "123@1"
["storage","mysql","u_db","internal_ip"]    "10.176.192.120"
["storage","mysql","u_db","internal_port"]  3306
["storage","mysql","a","database"]  "a"
["storage","mysql","a","username"]  "user"
["storage","mysql","a","password"]  "122a@1"

but what if add config param to determine how output look like and go with exporting this variables as env variables like

storage_mysql_u_db_internal_port=3306
storage_mysql_a_database=a
storage_mysql_a_username=user
storage_mysql_a_password=122a@1

which make it easy to be evaluated with eval as environment variable.

Not exactly what you're asking for, but I use the following two functions for extracting values from the JSON.sh output:

#function to get value of specified key
#returns empty string if not found
#warning - does not validate key format (supplied as parameter) in any way, simply returns empty string for malformed queries too
#usage: VAR=$(getkey foo.bar) #get value of "bar" contained within "foo"
#       VAR=$(getkey foo[4].bar) #get value of "bar" contained in the array "foo" on position 4
#       VAR=$(getkey [4].foo) #get value of "foo" contained in the root unnamed array on position 4
function getkey {
    #reformat key string (parameter) to what JSON.sh uses
    KEYSTRING=$(sed -e 's/\[/\"\,/g' -e 's/^\"\,/\[/g' -e 's/\]\./\,\"/g' -e 's/\./\"\,\"/g' -e '/^\[/! s/^/\[\"/g' -e '/\]$/! s/$/\"\]/g' <<< "$@")
    #extract the key value
    FOUT=$(grep -F "$KEYSTRING" <<< "$JSON_PARSED")
    FOUT="${FOUT#*$'\t'}"
    FOUT="${FOUT#*\"}"
    FOUT="${FOUT%\"*}"
    echo "$FOUT"
}

#function returning length of array
#returns zero if key in parameter does not exist or is not an array
#usage: VAR=$(getarrlen foo.bar) #get length of array "bar" contained within "foo"
#       VAR=$(getarrlen) #get length of the root unnamed array
#       VAR=$(getarrlen [2].foo.bar) #get length of array "bar" contained within "foo", which is stored in the root unnamed array on position 2
function getarrlen {
    #reformat key string (parameter) to what JSON.sh uses
    KEYSTRING=$(sed -e '/^\[/! s/\[/\"\,/g' -e 's/\]\./\,\"/g' -e 's/\./\"\,\"/g' -e '/^$/! {/^\[/! s/^/\[\"/g}' -e '/^$/! s/$/\"\,/g' -e 's/\[/\\\[/g' -e 's/\]/\\\]/g' -e 's/\,/\\\,/g' -e '/^$/ s/^/\\\[/g' <<< "$@")
    #extract the key array length - get last index
    LEN=$(grep -o "${KEYSTRING}[0-9]*" <<< "$JSON_PARSED" | tail -n -1 | grep -o "[0-9]*$")
    #increment to get length, if empty => zero
    if [ -n "$LEN" ]; then
        LEN=$(($LEN+1))
    else
        LEN="0"
    fi
    echo "$LEN"
}

It expects the JSON.sh to be run with the -l flag and output stored in the variable $JSON_PARSED.

Also, using eval as you suggested can be dangerous if the output is improperly escaped. For example, string "; rm -rf /" in the JSON data could lead to disaster.

So how about adding these to JSON.sh itself? That way you could source it, parse the json once and query away.

Also, how would you get a list of keys in an object?

Depends on the format you'd like. If the subset of JSON structure is OK for you, just use it without the -l option and specify a "path" to the object in question. In this case, my code snippet should give you this substructure.
If you really want a simple list of strings, you could re-parse this subset with JSON.sh and just extract (grep + regex) the first key strings on each line from the output, removing duplicates.

Hi,

I also was looking for a solution to "slurp" JSON.sh output into an bash array.
if you output only the leafs with JSON.sh -s -b -n this will do the trick:

source <( printf 'declare -A JSON=( %s )' "$(JSON.sh -s -b -n <input | sed  -E -e 's/\t/=/g' -e 's#\\#\\\\#g')" )

this will be sourced "in place" as:

declare -A JSON=( ["ok"]="true" ["result",0,"update_id"]=146860800 ["result",0,"message","message_id"]=6541 ["result",0,"message","text"]="\\ud83d\\ude02\\ud83d\\ude1d\\ud83d\\udc4c\\u263a\\u2764\\ud83d\\ude15\\ud83d\\ude08#\\u20e3\\ud83c\\udf0f\\ud83c\\udf89\\ud83d\\ude4a\\ud83d\\ude49\\u2615\\ud83d\\ude80\\u2708\\ud83d\\ude82\\ud83d\\udcaf\\u2714\\u303d\\ud83d\\udd1a" ["result",0,"message","from","id"]=123456789 ["result",0,"message","from","is_bot"]="false" ["result",0,"message","from","first_name"]="Kay" ["result",0,"message","from","last_name"]="M" ["result",0,"from","username"]="Gnadelwartz" ["result",0,"message","from","language_code"]="de" ["result",0,"message","chat","id"]=123456789 ["result",0,"message","chat","first_name"]="Test" ["result",0,"message","chat","last_name"]="Bot" ["result",0,"message","chat","username"]="BotTest" ["result",0,"message","chat","title"]="BotTestTitle" ["result",0,"message","chat","type"]="private" ["result",0,"message","date"]=1555822879 )

Now you can use bash array syntax to access the values:

echo ${JSON[ok]}
true

echo ${JSON["result",0,"message","message_id"]}
6541

echo ${JSON["result",0,"update_id"]}
146860800

echo ${JSON["result",0,"message","from","username"]}
Gnadelwartz

echo ${JSON["result",0,"message","photo",4,"file_id"]}
AgADAgADL6oxG-Gw4EndCWGl2WUfUo1pXw8ABDsKqM0vfngJavgDAAEC

In bashbot this makes parsing and assigning JSON five times faster

In case you want to ask how to iterate over the array, see https://stackoverflow.com/questions/3112687/how-to-iterate-over-associative-arrays-in-bash