jq while loop with variable produces error: Invalid path expression with result 0

Viewed 102

Consider

$ jq -n '0 as $i | while($i<3; $i+=1)'
null
jq: error (at <unknown>): Invalid path expression with result 0

I was expecting output of something like 0 1 2 but I get this error.

What am I doing wrong?

1 Answers

You are using variables wrong. You cannot just assign a value to a variable like $i = 1 or update it like $i += 1.

Variables behave similar to other functions/filters, in the sense that they produce their value when evaluated, and that they have to be defined using the as construction (just like def for functions) before they can be used. The assignment operator = and its update variants like +=, on the other hand, only work for the context or a subset of the context. You can set . = 1 (which can more simply be written as just 1), or, if appropriate, a given subset like .a[0].b += 1.

You may want to have a look at the variables section, and the assignment section of the manual; especially the part in the assignment section reading

Note that the LHS of assignment operators refers to a value in .. Thus $var.foo = 1 won't work as expected ($var.foo is not a valid or useful path expression in .); use $var | .foo = 1 instead.

Your example without variables works as expected. The context is being modified during the loop:

$ jq -n '0 | while(.<3; .+1)'
0
1
2

Referring to this part in the variable section reading

The expression exp as $x | ... means: for each value of expression exp, run the rest of the pipeline with the entire original input, and with $x set to that value. Thus as functions as something of a foreach loop.

you can implement that loop using a variable like so:

$ jq -n '(0,1,2) as $i | $i'
0
1
2

Or so:

$ jq -n 'range(3) as $i | $i'
0
1
2

Note that the variable definition only takes care of the looping through the values (by producing multiple contexts). The generation of the different values needs to be taken care of separately. And here, you can employ your while loop:

$ jq -n '0 | while(.<3; .+1) as $i | $i'
0
1
2
Related