melon@machine: ~/$ cat /tmp/test.json
[
"One Entry Here",
"Two Entry Here",
"Three Entry Here",
"Four Entry Here"
]
melon@machine: ~/$ jq -sr '.[]| @sh' /tmp/test.json
'One Entry Here' 'Two Entry Here' 'Three Entry Here' 'Four Entry Here'
melon@machine: ~/$ BANANA=( 'One Entry Here' 'Two Entry Here' 'Three Entry Here' 'Four Entry Here' )
melon@machine: ~/$ echo ${BANANA[1]}
Two Entry Here
The above shows the expected behavior, and shows me manually setting $BANANA
to the output of the jq
command.
This behavior changes if the variable uses command substitution instead:
melon@machine: ~/$ BANANA=( $(jq -sjr '.[]| @sh' /tmp/test.json) )
melon@machine: ~/$ echo ${BANANA[1]}
melon@machine: ~/$ echo ${BANANA[0]}
'One Entry Here' 'Two Entry Here' 'Three Entry Here' 'Four Entry Here'
While it is true that I am trying to convert a JSON array into a BASH array to iterate over, and there are other suggested methods, my question is Why is the behavior different here when using command substitution, and is there anything that I can do to have the command substitution behave like when I manually copy and paste the jq
output into the variable myself?
GNU bash, version 5.0.3(1)-release (x86_64-pc-linux-gnu)
GNU bash, version 5.1.4(1)-release (x86_64-pc-linux-gnu)
melon@machine: ~/$ mapfile -t BANANA < <(jq '.[]' /tmp/test.json)
melon@machine: ~/$ echo ${BANANA[0]}
"One Entry Here"
melon@machine: ~/$ echo ${BANANA[1]}
"Two Entry Here"
mapfile
works, but I'm still curious about the difference when using command substitution.
Even after adding the -j
flag to jq
to suppress ending newline, the results are the same.
I would do one of:
which gives the expected:
Or use
declare
which is kind of likeeval
but just for variable assignments:This forces the shell to do a 2nd round of expansions so that the quotes emitted by jq will be process properly by the shell. Otherwise you get:
or