summaryrefslogtreecommitdiffhomepage
path: root/jq.html.markdown
diff options
context:
space:
mode:
authorJack Kuan <kjkuan@gmail.com>2022-06-04 02:56:47 -0400
committerJack Kuan <kjkuan@gmail.com>2022-06-04 02:56:47 -0400
commit0ef85542ef8d8d3f744fa94d1d9e03feb04c6b6d (patch)
tree5096d83eb4a39a9a54ae3e678b423fe9ab0c3dda /jq.html.markdown
parent2257d6bae2960c436295ce7c6da45151ea7a7d3d (diff)
Introduce function definition, and add more examples.
Diffstat (limited to 'jq.html.markdown')
-rw-r--r--jq.html.markdown84
1 files changed, 75 insertions, 9 deletions
diff --git a/jq.html.markdown b/jq.html.markdown
index 3691baaf..3b756890 100644
--- a/jq.html.markdown
+++ b/jq.html.markdown
@@ -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