Use slurp mode:
o --slurp/-s: Instead of running the filter for each JSON object in the input, read the entire input stream into a large array and run the filter just once.
$ jq -s '.' < tmp.json
[
{
"name": "John",
"email": "[email protected]"
},
{
"name": "Brad",
"email": "[email protected]"
}
]
Answer from chepner on Stack OverflowCreating an array from objects?
More fun with jq, getting results into a usable array
How to use jq to convert an bash array in command line to json array? - Unix & Linux Stack Exchange
bash - Add JSON objects to array using jq - Unix & Linux Stack Exchange
I'm using this in a cURL to get the data from result[]:
foo=$(curl --request GET \ --silent \ --url https://example.com \ --header 'Content-Type: application/json' | jq -r '.result[]')
When I print $foo, this is what I have:
[key]
default
firewall_custom
zone
34
[
{
"id": "example",
"version": "6",
"action": "block",
"expression": "lorem",
"description": "ipsum",
"last_updated": "2024-08-15T19:10:24.913784Z",
"ref": "example",
"enabled": true
},
{
"id": "example2",
"version": "7",
"action": "block",
"expression": "this",
"description": "that",
"last_updated": "2024-08-15T19:10:24.913784Z",
"ref": "example2",
"enabled": true
}
]What I need from this is to create a loop where, in a series of addtional cURLs, I can insert action, expression, and description.
I'm imagining that I would push these to 3 separate arrays (action, expression, and description), so that ${action[0]} would coincide with ${expression[0]} and ${description[0]}, and so on.
Something along the lines of:
# assuming that I have somehow created the following arrays:
# action=("block" "block")
# expression=("lorem" "this")
# description=("ipsum" "that")
for x in ${action[@]}; do
bar=$(curl --request GET \
--silent \
--url https://example.com \
--data '{
"action": ${action[$x]},
"expression": ${expression[$x]},
"description": ${description[$x]}
}' | jq '.success')
if [[ $bar == true ]]
then
printf "$x succeeded\n"
else
printf "$x failed\n"
fi
# reset bar
bar=''
doneThe question is, how to create action, expression, and description arrays from the results of $foo (that original cURL)?
This trick with the jq 1.5 inputs streaming filter seems to do it
... | jq -n '.items |= [inputs]'
Ex.
$ find ~/ -maxdepth 1 -name "D*" |
while read line; do
jq -n --arg name "$(basename "$line")" \
--arg path "$line" \
'{name: $name, path: $path}'
done | jq -n '.items |= [inputs]'
{
"items": [
{
"name": "Downloads",
"path": "/home/steeldriver/Downloads"
},
{
"name": "Desktop",
"path": "/home/steeldriver/Desktop"
},
{
"name": "Documents",
"path": "/home/steeldriver/Documents"
}
]
}
Calling jq directly from find, and then collecting the resulting data with jq to construct the final output, without any shell loops:
find ~ -maxdepth 1 -name '[[:upper:]]*' \
-exec jq -n --arg path {} '{ name: ($path|sub(".*/"; "")), path: $path }' \; |
jq -n -s '{ items: inputs }'
The jq that is being executed via -exec creates a JSON object per found pathname. It strips off everything in the pathname up to the last slash for the name value, and uses the pathname as is for the path value.
The final jq reads the data from find into an array with -s, and simply inserts it as the items array in a new JSON object. The final jq invocation could also be written jq -n '{ items: [inputs] }.
Example result (note that I was using [[:upper:]* in place of D* for the -name pattern with find):
{
"items": [
{
"name": "Documents",
"path": "/home/myself/Documents"
},
{
"name": "Mail",
"path": "/home/myself/Mail"
},
{
"name": "Work",
"path": "/home/myself/Work"
}
]
}