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 ): Cannot index number with number jq -n '"abc" | .name' # => jq: error (at ): Cannot index string with string "name" jq -n '{"a": 97} | .[0]' # => jq: error (at ): Cannot index object with number -jq -n '[89, 64] | .["key"]' # => jq: error (at ): Cannot index array with string "key" +jq -n '[89, 64] | .["key"]' # => jq: error (at ): 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