jq - Access array index in a loop
If your json contains a list of objects, jq allows you to access such elements using an array index filter jq '.[index]' someData.json. But the value index is static, say jq '.[2]' someData.json.
How can I access the element at position index when the value of index is dynamic, such as when in loops?
What I want to do is, when in a loop, call jq to access an element at some index that I specify.
In pseudocode, it’d look something like this :
1
2
3
4
5
6
array=[ {"name": "a"}, {"name": "b"}, {"name": "c"} ]
for (( i = 0; i < $array.length; i++ ))
do
element = jq '[$i]' $array
echo "element = $element"
done
What worked - using --argjson
For that to work, we need to be in the context of jq, where:
- we declare a variable and assign it a value;
- and then use that variable as an argument for the array index.
That means:
- Using
--argjsonto assign a numeric variable that’s passed tojqas the index of the array. It has the form:--argjson myIndex $i '.[$myIndex]'- The first part,
--argjson myIndex $i, defines variablemyIndexand assigns the value of$ito it. - The second part,
'.[$myIndex]', passes the argument$myIndexto the array index filter.
- The first part,
- Using
--raw-outputto get the result that’s not “formatted as a JSON string with quotes”.
Let the variable jsonData hold example json. I came across storing json in a bash variable on Stackoverflow
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
# load json data
jsonData=$(cat <<EOF
[
{
"id": 1,
"name": "One"
},
{
"id": 2,
"name": "Two"
},
{
"id": 3,
"name": "Three"
}
]
EOF
)
numberOfItems=$(echo $jsonData | jq --raw-output length)
# loop over the list in json
for (( i=0; i<numberOfItems; i++ ))
do
echo "At index, $i"
# assign a numerical variable that's passed to jq as the array index
name=$( echo $jsonData | jq --raw-output --argjson myIndex $i '.[$myIndex].name' )
echo "Name=$name"
done
What didn’t work - using variables not in jq context
Using the i in the loop directly as the index of the array didn’t work.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
jsonData=$(cat <<EOF
[
{
"id": 1,
"name": "One"
},
{
"id": 2,
"name": "Two"
},
{
"id": 3,
"name": "Three"
}
]
EOF
)
numberOfItems = $(echo $jsonData | jq --raw-output length)
# loop over the list in json
for (( i=0; i<numberOfItems; i++ ))
do
echo "At index, $i"
# passing i directly doesn't work
name=$( echo $jsonData | jq --raw-output '.[$i].name' )
echo "name=$name"
done
That returned error
1
2
3
jq: error: $i is not defined at <top-level>, line 1:
.[$i].name
jq: 1 compile error
Why? Although i is defined in the shell script, it’s not defined in the jq’s context. So jq has no idea about ì.
What didn’t work - using --arg
Using --arg name value also didn’t work.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
jsonData=$(cat <<EOF
[
{
"id": 1,
"name": "One"
},
{
"id": 2,
"name": "Two"
},
{
"id": 3,
"name": "Three"
}
]
EOF
)
numberOfItems = $(echo $jsonData | jq --raw-output length)
# loop over the list in json
for (( i=0; i<numberOfItems; i++ ))
do
echo "At index, $i"
# using --arg doesn't work
name=$( echo $jsonData | jq --raw-output --arg myIndex $i '.[$myIndex].name' )
echo "name=$name"
done
I’m assigning i to variable myIndex so as to pass it to jq. But that fails with
1
jq: error (at jsonData.json:2): Cannot index array with string "0"
Why? Because --arg assigns a variable as a String, but jq’s array index must be a number.
References
jqdocumentation: https://stedolan.github.io/jq/manual/#InvokingjqStackoverflow: https://stackoverflow.com/questions/52609226/how-i-pass-argument-as-index-to-jq