From Json structure, I want a specific dictionary. From key's color yellow or red, I add id value.
[
{
"id": "9b058640",
"type": "db",
"color": "red",
"host": "db1"
},
{
"id": "0u858640",
"type": "db",
"color": "yellow",
"host": "db2"
},
{
"id": "0ui9k40",
"type": "net",
"color": "red",
"host": "net1"
},
{
"id": "5ty87a",
"type": "net",
"color": "yellow",
"host": "net2"
}
]
So I want to get the X dictionary
X=(
['yellow']="9b058640 5ty87a"
['red']="9b058640 0ui9k40"
)
I could parse by value :
jq -c '.[] | select(.color | contains("red"))'
CodePudding user response:
You can use the @tsv operator in jq to emit tab-separated output, which a bash while read loop can easily parse as input.
Assuming your input JSON is in the variable s:
declare -A X=( )
while IFS=$'\t' read -r color id; do
X[$color] ="$id "
done < <(jq -r '.[] | [.color, .id] | @tsv' <<<"$s")
The above does take a minor shortcut in that it leaves a trailing space after each item. If that's unacceptable for some reason, you can always go through the array and clean it up after the fact with a second loop:
for color in "${!X[@]}"; do
X[$color]=${X[$color]%" "}
done
You can see this running in the sandbox at https://replit.com/@CharlesDuffy2/IndigoRemoteEngineering
Alternately, using eval:
#!/usr/bin/env bash
case $BASH_VERSION in ''|[0-3].*) echo "ERROR: bash 4.0 required" >&2; exit 1;; esac
declare -A X=( )
eval "$(
jq -r '
reduce .[] as $item ({}; .[$item.color] = [$item.id])
| to_entries[]
| "X[\(.key | @sh)]=\(.value | join(" ") | @sh)"
'
)" <file.json
CodePudding user response:
No need for ., source, eval or even looping in bash. All you need is declare and jq, which can construct the declaration using escaping with @sh and string interpolation:
declare -A X="($(
jq -r '
[ ("yellow", "red") as $color
| @sh "[\($color)]=\(map(select(.color == $color).id) | join(" "))"
] | join(" ")
' input.json
))"
$ echo "${X[yellow]}"
0u858640 5ty87a
$ echo "${X[red]}"
9b058640 0ui9k40
CodePudding user response:
Answer:
declare -A a
. <(jq -r '"a[\(.color)] =${a[\(.color)] }\(.id)"' file.json)
Provides:
$ declare -p a
$ declare -A a=([red]="9b058640 0ui9k40" [yellow]="0u858640 5ty87a" )
# or
$ echo "${a[red]}"; echo "${a[yellow]}"
9b058640 0ui9k40
0u858640 5ty87a
Explanation:
- Construct the following bash code in
jq: a[color] =${a[color] }id${a[color] }expands to, only ifa[color]is empty."\(.id)"is jq string interpolation - its replaced with the value of.id- use
.and a process sub to source this code
