I'm trying to create a dynamic json data using jq, but I don't know how to write it when involving loop. I can do this in normal bash writing a sequence string
Here is the example code:
#!/bin/bash
# Here I declare 2 arrays just to demonstrate. Each values pairs between `disk_ids` and `volume_ids` cannot have the same value. If one has value, the other must null.
disk_ids=(111 null 222 333)
volume_ids=(null 444 null null)
json_query_data=""
# Now example I want to loop through the above 2 arrays and create json. In real application I already have the above arrays that is looping where I can access using $disk_id and $volume_id.
for disk_id in "${disk_ids[@]}"; do
for volume_id in "${volume_ids[@]}"; do
json_query_data=$(jq -n --argjson disk_id "$disk_id" --argjson volume_id "$volume_id" '{
devices: {
sda: {"disk_id": $disk_id, "volume_id": $volume_id },
sdb: {"disk_id": $disk_id, "volume_id": $volume_id },
sdc: {"disk_id": $disk_id, "volume_id": $volume_id },
sdd: {"disk_id": $disk_id, "volume_id": $volume_id },
}}')
done
done
As you can see that is definitely NOT the output that I want, and my code writing logic is not dynamic. The final output should produce the following json when I echo "${json_query_data}"
:
{
devices: {
sda: {"disk_id": 111, "volume_id": null },
sdb: {"disk_id": null, "volume_id": 444 },
sdc: {"disk_id": 222, "volume_id": null },
sdd: {"disk_id": 333, "volume_id": null },
}}
I have not seen any example online regarding looping with variable when creating json data with jq
. Appreciate if someone can help. Thanks.
UPDATE:
I must use for loop inside bash to create the json data. Because the sample array disk_ids
and volume_ids
that I provided in the code were just example, In real application I already able to access the variable $disk_id
and $volume_id
for each for loop counter. But how do I use this variables and create the json output that fill up all the data above inside that for loop?
The json example is taken from: linode API here
CodePudding user response:
The looping/mapping can also be accomplished in jq:
#!/bin/bash
disk_ids=(111 null 222 333)
volume_ids=(null 444 null null)
jq -n --arg disk_ids "${disk_ids[*]}" --arg volume_ids "${volume_ids[*]}" '
[$disk_ids, $volume_ids | . / " " | map(fromjson)] | transpose
| {devices: with_entries(
.key |= "sd\([. 97] | implode)"
| .value |= {disk_id: first, volume_id: last}
)}
'
{
"devices": {
"sda": {
"disk_id": 111,
"volume_id": null
},
"sdb": {
"disk_id": null,
"volume_id": 444
},
"sdc": {
"disk_id": 222,
"volume_id": null
},
"sdd": {
"disk_id": 333,
"volume_id": null
}
}
}
If you insist on doing this in a bash loop, how about:
#!/bin/bash
disk_ids=(111 null 222 333)
volume_ids=(null 444 null null)
json='{"devices": {}}'
for i in ${!disk_ids[@]}
do
json="$(
jq --argjson disk_id "${disk_ids[$i]}" --argjson volume_id "${volume_ids[$i]}" '
.devices |= . {"sd\([length 97] | implode)": {$disk_id, $volume_id}}
' <<< "$json"
)"
done
echo "$json"