Recall that a jq program is a pipeline of expressions.
Variable assigmnent follows this rule: a variable assignment is an expression that looks like:
... | expr as $varname | ...
Like the identity expression ., the variable assignment's output is the same as its input.
Setting the variable's value is a side-effect.
Example, showing . after the assignment is the same as the initial input:
$ jq -c -n '42 | (. * 2) as $double | [., $double]'
[42,84]
The scope of the variable is "lexical" -- the variable will be in scope for the rest of the pipeline. Variables defined in functions (we'll get to functions later) are "local" to the function.
The variable must begin with $.
The rest of the variable name is an identifier: starts with a letter or underscore followed by letters, numbers or underscores.
From the manual:
Multiple variables may be declared using a single
asexpression by providing a pattern that matches the structure of the input (this is known as "destructuring").
Examples:
[1, 2, 3] as [$a, $b, $c]
| [$a, $b, $c] # => [1, 2, 3]
{"foo": "bar", "len": [10, 20]} as {foo: $f, len: [$h, $w]}
| [$f, $h, $w] # => ["bar", 10, 20]
Matching the variable name to the object key offers a shortcut:
{"x": 4, "y": 7} as {$x, $y}
| [$x, $y] # => [4, 7]
{"foo": "bar", "len": [10, 20]} as {$foo, $len}
| [$foo, $len] # => ["bar", [10, 20]]
The same shortcut works in the reverse sense for object construction
4 as $x | 7 as $y | {$x, $y} # => {"x":4, "y": 7}
As shown in the above example, variables are handy for storing constants. It's better to give constants a name rather than have "magic numbers" show up in the code.
It is often more readable to omit variables.
Consider calculating the average of a list of numbers
[2, 4, 8, 7]
| add as $sum
| length as $len
| $sum / $len
compared to
[2, 4, 8, 7] | add / length
This highlights one of the most powerful aspects of jq: the input to a filter is provided to every sub-expression:
[2,4,8,7] is passed to add (which sums the numbers by applying the + operator to all the elements)[2,4,8,7] is also passed to length
jq operators you'll need for the learning exercise//
The expression a // b outputs b if a is false or null, otherwise it outputs a.
In the context of setting a variable, this is very handy for providing a default value:
(.input.theAnswer // 42) as $answer | ...
+, -, * are the usual numeric addition, subtraction and multiplication operators.In this exercise you're going to write some code to help you make a brilliant lasagna from your favorite cookbook.
You have four tasks, all related to the time spent cooking the lasagna.
Define a constant named $expected_minutes_in_oven.
According to the cookbook, the expected oven time in minutes is 40:
$ jq -n -f lasagna.jq
{
"expected_minutes_in_oven": 40,
...
This value takes the actual minutes the lasagna has been in the oven as input and returns how many minutes the lasagna still has to remain in the oven, based on the expected oven time in minutes from the previous task.
$ echo '{"actual_minutes_in_oven": 18}' | jq -f lasagna.jq
{
"expected_minutes_in_oven": 40,
"remaining_minutes_in_oven": 22,
...
The preparation time is how long it takes to get the lasagna ready before it is put in the over. It takes 2 minutes to prepare each layer.
$ echo '{"number_of_layers": 3}' | jq -f lasagna.jq
{
...
"preparation_time": 6,
...
Calculate how many minutes in total you've worked on cooking the lasagna. This is the sum of the preparation time in minutes and the time in minutes the lasagna has spent in the oven at the moment.
$ echo '{"actual_minutes_in_oven": 10, "number_of_layers": 2}' | jq -f lasagna.jq
{
...
"total_time": 14,
...
Sign up to Exercism to learn and master jq with 12 concepts75 exercises, and real human mentoring, all for free.