Introduce function definition, and add more examples.

This commit is contained in:
Jack Kuan 2022-06-04 02:56:47 -04:00
parent 2257d6bae2
commit 0ef85542ef

View File

@ -362,7 +362,7 @@ jq -n '.unknown_key // 7' # => 7
jq -n '123 | .[0]' # => jq: error (at <unknown>): Cannot index number with number
jq -n '"abc" | .name' # => jq: error (at <unknown>): Cannot index string with string "name"
jq -n '{"a": 97} | .[0]' # => jq: error (at <unknown>): Cannot index object with number
jq -n '[89, 64] | .["key"]' # => jq: error (at <unknown>): Cannot index array with string "key"
jq -n '[89, 64] | .["key"]' # => jq: error (at <unknown>): Cannot index array with string "key"
# You can, however, append a `?` to a lookup to make jq return `empty`
# instead when such error happens.
@ -443,7 +443,19 @@ jq -n '{ values: ({ a: 1, b: 2, c: 3 }[] | . * 2) }'
# Conditional `if ... then ... else ... end` in jq is an expression, so
# both the `then` part and the `else` part are required.
# both the `then` part and the `else` part are required. In jq, only
# two values, `null` and `false`, are false; all other values are true.
#
jq -n 'if 1 > 2 | not and 1 <= 2 then "Makes sense" else "WAT?!" end'
# Output
# "Makes sense"
# Notice that `not` is a built-in function that takes zero arguments,
# that's why it's used as a filter to negate its input value.
# We'll talk about functions soon.
# Another example using a conditional:
#
jq -n '1, 2, 3, 4, 5 | if . % 2 != 0 then . else empty end'
@ -608,7 +620,7 @@ echo $numbers | jq -rs ' # Slurp the numbers into an array.
| # For each object, generate two lines:
"Group \(.key): \(.value | sort | join(" "))" + "\n" +
"Average: \( .value | (add / length) )"
] # Contain the group+average lines in an array.
# Join the array elements by separator lines (dashes) to produce the report.
| join("\n" + "-"*78 + "\n")
@ -682,7 +694,7 @@ jq -n '["a", "b", "c"] | reduce .[] as $i (""; . + $i)' # => "abc"
#
# reduce (1, 2, 3, 4, 5) as $i (0; . + $i)
#
# can be think of as doing:
# can be think of as doing:
#
# 0 + 1 | . + 2 | . + 3 | . + 4 | . + 5
#
@ -730,7 +742,7 @@ jq -rn '[1, 2, 3, 4, 5]
# With the `expr as $var` form, if multiple values are generated by `expr`
# then jq will iterate through them and bind each value to `$var` in turn
# for the rest of the pipeline.
#
#
jq -rn 'range(2; 4) as $i
| range(1; 6) as $j
| "\($i) * \($j) = \($i * $j)"
@ -749,6 +761,26 @@ jq -rn 'range(2; 4) as $i
# 3 * 5 = 15
# It's sometimes useful to bind the initial input to a variable at the
# start of a program, so that you can refer to it later down the pipeline.
#
jq -rn "$(cat <<'EOF'
{lookup: {a: 1, b: 2, c: 3},
bonuses: {a: 5, b: 2, c: 9}
}
| . as $doc
| .bonuses
| to_entries[]
| "\(.key)'s total is \($doc.lookup[.key] + .value)"
EOF
)"
# Output:
# a's total is 6
# b's total is 4
# c's total is 12
# In jq, values can be assigned to an array index or object key via the
# assignment operator, `=`. The same current input is given to both sides
# of the assignment operator, and the assignment itself evaluates to the
@ -761,7 +793,7 @@ jq -n '.a = 1 | .b = .a + 1' # => {"a": 1, "b": 2}
# filter, and assiging to a key under `null` turns it into an object with
# the key. The same input (now an object) then gets piped to the next filter,
# which then sets the `b` key to the value of the `a` key plus `1`, which is `2`.
#
#
# Another example:
#
@ -799,9 +831,43 @@ jq -n '{a: 1, b: {c: 2}, d: [3, 4, 5]} | del(.b.c, .d[1]) | .b.x = 6'
# ]
# }
# FIXME: Cover more topics
# - function definition
# - ...
# Other than using jq's built-in functions, you can define your own.
# In fact, many built-in functions are defined using jq (see the link
# to jq's built-in functions at the end of the doc).
#
jq -n '
def my_select(expr): if expr then . else empty end;
def my_map(expr): [.[] | expr];
def sum: reduce .[] as $x (0; . + $x);
def my_range($from; $to):
if $from >= $to then
empty
else
$from, my_range($from + 1; $to)
end
;
[my_range(1; 6)] | my_map(my_select(. % 2 != 0)) | sum
'
# Output:
# 9
# Some notes about function definitons:
#
# - Functions are usually defined at the beginning, so that they are available
# to the rest of the jq program.
#
# - Each function definion should end with a `;` (semicolon).
#
# - It's also possible to define a function within another, though it's not shown here.
#
# - Function parameters are separated by `;` (semicolor). This is consistent with
# passing multiple arguments when calling a function.
#
# - `def f($a; $b): ...;` is a shorthand for: `def f(a; b): a as $a | b as $b | ...`
#
```
## Further Reading