36

How do I parse a json array of objects to a bash array with those objects as strings?

I am trying to do the following:

CONVO=$(get_json_array | jq '.[]')
for CONVERSATION in $CONVERSATIONS
do
    echo "${CONVERSATION}"
done

But the echo prints out lines instead of the specific objects. The format of the object is:

{ "key1":"value1", "key2": "value2"}

and I need to pass it to an api:

api_call '{ "key1":"value1", "key2": "value2"}'
1

5 Answers 5

68

The problem is that jq is still just outputting lines of text; you can't necessarily preserve each array element as a single unit. That said, as long as a newline is not a valid character in any object, you can still output each object on a separate line.

get_json_array | jq -c '.[]' | while read object; do
    api_call "$object"
done

Under that assumption, you could use the readarray command in bash 4 to build an array:

readarray -t conversations < <(get_json_array | jq -c '.[]')
for conversation in "${conversations[@]}"; do
    api_call "$conversation"
done
Sign up to request clarification or add additional context in comments.

4 Comments

+1. Re: "as long as a newline is not a valid character in any object": Since these are JSON objects, that's not a concern.
Ah, I was under the mistaken assumption that a newline could appear in a hash value, but it looks like they are required to be encoded as \n.
If you use jq -j instead of jq -r, there's no separator added by JQ itself, so you can add your own (such as NUL literals) from your jq code.
Just want to point out that the iteration variable have to be called the same in loop header and body (conversion vs. conversation). Can't improve the answer as the change is as little as 2 characters and StackOverflow expects at least 6 characters to be changed.
1

Here is a solution without loops:

json=$(jq -c ".my_key[]"  ./my-file.json)
json_without_quotes=$(echo ${json//\"/""})
declare -a all_apps_array=($(echo $json_without_quotes | tr "\n" " "))

3 Comments

Instead of second line you can use jq -r which prints raw JSON (discards quotes).
doesn't work if there are spaces.
A one-line solution would be declare -a all_apps_array =($(jq -r ". my_key[]" ./my-file.json | tr "\n" " "))
0

Also another option without having to loop.

jq -c ".response[]"  "${file}" | sed 's/[{|}]//g' | tr ',' '\n' | sed 's/"//g' | awk -F":" '{print toupper($1)":"$2}'

Hope it helps someone

Comments

0

Credit for this approach goes to @ingernet. No jq required. This uses sed to remove [, ], and ,, leaving a space between so it can be wrapped with ().

newArray=( $(echo $jsonArrayString | sed -e 's/\[//g' -e 's/\]//g' -e 's/\,/ /g') );

1 Comment

This is severely buggy. If your string is "foo * bar", the * will be replaced with a list of filenames, and that's just the first of many problems that came to mind.
0

This should convert a json array to a bash array regardless of the contents of the json entries. I needed it to pass a list of files to a linter inside of a github action. It was important to make a single call to the linter rather than one call per file to get the output I needed. It works in bash 3.2

count=$(jq length <<< "$pr_files")
declare -a files=()
for (( i=0; i < count; i++ ))
do
    file=$(jq -r ".[$i]" <<< "$pr_files")
    files+=( "$file" )
done

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.