1

I can create a json object with an array using jq like this

echo '{"input":{"names":[]}}' | jq --arg val "alice" '.input.names[0] += $val'| jq --arg val "bob" '.input.names[1] += $val'

which gives

{
  "input": {
    "names": [
      "alice",
      "bob"
    ]
  }
}

Now I want to recreate this in a shell script where "names" come from a shell array

#!/bin/sh

names=( alice bob )
                 
ITER=0
for i in "${names[@]}"
do                  
    echo '{"input":{"names":[]}}' |  jq --arg val "$i" '.input.names[$ITER] += $val'
    echo ${I} ${ITER}                                                               
    ITER=$(expr $ITER + 1)                                                          
done  

but I run into

jq: error: $ITER is not defined at <top-level>, line 1:
.input.names[$ITER] += $val             
jq: 1 compile error
0
jq: error: $ITER is not defined at <top-level>, line 1:
.input.names[$ITER] += $val             
jq: 1 compile error
1
3
  • Either assign (=, not +=) to an array index jq --arg val "alice" '.input.names[0] = $val', or append (+=) to an array using no index and the array brackets on the RHS: jq --arg val "alice" '.input.names += [$val]'. Commented May 12, 2022 at 12:52
  • i tried echo '{"input":{"names":[]}}' | jq --arg val "$i" '.input.names += [$val]' but it just creates two different objects Commented May 12, 2022 at 12:58
  • Because you don't capture the output of an iteration step, so you lose the output from one call and start all over again in the next. I have added a bash solution implementing your for loop while capturing the outputs. Commented May 12, 2022 at 13:09

2 Answers 2

3

You could get rid of the shell loop and use one jq call:

names=( alice bob )
jq -n --arg names "${names[*]}" '{"input": {"names": ($names / " ") } }'

or

names=( alice bob )
printf '%s\0' "${names[@]}" |
jq -sR '(. / "\u0000") as $names | { "input": { "names": $names } }'
Sign up to request clarification or add additional context in comments.

2 Comments

If I replace \0 in the printf variant with | (and of course \u0000 too) then the array is ["alice","bob",""]. So why is this not the case with \0?
I don't know the reason. It might be a long standing bug that \u0000 is treated this way, it's convenient though
2

You don't capture the output of an iteration step, so you lose the output from the jq call and start all over again in the next iteration step.

Here's a bash solution which captures the output using $(...) and provides it for the next using <<<. (Note that there are better ways to solve this problem, e.g. without looping but by proving jq all elements to be added at once.)

json='{"input":{"names":[]}}'

for i in alice bob
do json="$(jq --arg val "$i" '.input.names += [$val]' <<< "$json")"
done

echo "$json"
{
  "input": {
    "names": [
      "alice",
      "bob"
    ]
  }
}

1 Comment

yep...that worked also... thanks

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.