There are many possibilities, but given that you have already written a bash for loop, you can start with this version of your script:
#!/bin/bash # Requires bash with associative arrays declare -A dict dict["foo"]=1 dict["bar"]=2 dict["baz"]=3 for i in "${!dict[@]}" do echo "$i" echo "${dict[$i]}" done | jq -n -R 'reduce inputs as $i ({}; . + { ($i): (input|(tonumber? // .)) })'
The result reflects the ordering of the keys created by the bash for loop:
{ "bar": 2, "baz": 3, "foo": 1 }
In general, a jq-based approach of key-value pairs, with one key per line, followed by the corresponding value on the next line, has a lot to recommend. The following is a general solution to this general pattern, but using NUL as the end of line character.
Keys and values ββas JSON objects
To make this more general, it would be better to represent keys and values ββas JSON objects. In this case, we could write:
for i in "${!dict[@]}" do echo "\"$i\"" echo "${dict[$i]}" done | jq -n 'reduce inputs as $i ({}; . + { ($i): input })'
Other options
JSON keys must be JSON strings, so some work may be required to ensure that the required mapping from bash keys to JSON keys is performed. Similar notes apply to mapping bash array values ββto JSON values. One way to handle arbitrary bash keys would be to let jq perform the conversion:
printf "%s" "$i" | jq -Rs .
Of course, you could do the same with the values ββof the bash array, and let jq check if the value can be converted to a number or some other type of JSON as desired (for example, using fromjson? // . ).
Common decision
Here is a general solution on the lines indicated in the jq FAQ, and is protected by @CharlesDuffy. It uses NUL as a separator when passing bash keys and values ββto jq, and has the advantage of requiring only one jq call. Optionally fromjson? // . filter fromjson? // . fromjson? // . can be omitted or replaced by another.
declare -A dict=( [$'foo\naha']=$'a\nb' [bar]=2 [baz]=$'{"x":0}' ) for key in "${!dict[@]}"; do printf '%s\0%s\0' "$key" "${dict[$key]}" done | jq -Rs ' split("\u0000") | . as $a | reduce range(0; length/2) as $i ({}; . + {($a[2*$i]): ($a[2*$i + 1]|fromjson? // .)})'
Output:
{ "foo\naha": "a\nb", "bar": 2, "baz": { "x": 0 } }