skip to Main Content

I need to loop through a dictionary and append records to a json object file option.json
the code I have is

for K in "${!MYMAP[@]}"; do 
    opt="{
        "OptionName":"${K}",
        "Value":"${MYMAP[$K]}"
        },"
    echo $opt >> option.json
done 

But this produce option.json as below

{
    "OptionName": "name",
    "Value": "test"
},
{
    "OptionName": "age",
    "Value": "13"
}

How do i make the option.json a json object and appending each {} inside the object, so my option.json would look like below

[
    {
        "OptionName": "name",
        "Value": "test"
    },
    {
        "OptionName": "age",
        "Value": "13"
    }
]

2

Answers


  1. If you omit the trailing comma in the initial production, you get a stream of inputs that jq can collect into an array using the --slurp (or -s) flag:

    for k in "${!mymap[@]}"; do 
      opt="{"OptionName":"${k}", "Value":"${mymap[$k]}"}"
      echo "$opt"                            # no comma here --^
    done | jq -s . > option.json
    

    However, you can also have jq do the JSON composition in the first place, guaranteeing valid JSON encoding even with challenging values (such as double quotes, etc.). For example, I’d use the --args option to import the bash array’s keys and values as positional parameters, and the $ARGS builtin to access them:

    declare -A mymap=([name]="test" [age]="13")
    
    jq -n '
      $ARGS.positional | [_nwise(length/2)] | transpose
      | map({OptionName: first, Value: last})
    ' --args "${!mymap[@]}" "${mymap[@]}" > option.json
    

    As @oguz pointed out, newer versions of bash can also expand arrays to their keys and values in our desired alternating order by using "${mymap[@]@k}". The full jq filter would then just read:

    jq -n '$ARGS.positional | [_nwise(2) | {OptionName: first, Value: last}]' 
      --args "${mymap[@]@k}"
    
    Login or Signup to reply.
  2. Sure it’s better to use jq if you work with json but in case when jq is not available printf can be used, like this:

    declare -A arr=([key1]=val1 [key2]=val2)
    
    items=$(
        for key in "${!arr[@]}"; {
            val=${arr[$key]}
            printf '{"%s": "%s"},n' "$key" "$val"
        }
    )
    
    echo "[${items%,*}]"
    [{"key2": "val2"},
    {"key1": "val1"}]
    

    Here is I’m using jq to validate the result:

    $ echo "[${items%,*}]" | jq
    [
      {
        "key2": "val2"
      },
      {
        "key1": "val1"
      }
    ]
    

    Note this syntax ${items%,*} it will print $items without last comma which is crucial for json.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search