jq Cheatsheet
Selecting and Filtering
Use this jq reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
select
select(f) emits its input unchanged when f is truthy, and nothing otherwise. It is the filter, not a loop.
jq -c '[.items[] | select(.price > 15)]' # [{"id":2,...,"price":20,...},{"id":3,...,"price":30,...}] jq -c '[.items[] | select(.cat == "x" and .price > 15) | .id]' # [3] jq -c '[.items[] | select(.cat == "x" or .id == 2) | .id]' # [1,2,3] jq -c '[.items[] | select(.name | test("^[ab]$")) | .id]' # [1,2] jq -c '[.items[] | select(has("cat")) | .id]' # [1,2,3]
Truthiness in jq is narrow: only false and null are falsy. 0, "", [], and {} are all truthy, which is the opposite of most languages.
jq -cn '[0, "", [], {}] | map(if . then "truthy" else "falsy" end)' # ["truthy","truthy","truthy","truthy"]
Negating a condition
not is a filter with no arguments, so it goes on the right of a pipe.
jq -c '[.items[] | select(.cat == "x" | not) | .id]' # [2] jq -c '[.items[] | select(.price > 15 | not) | .id]' # [1] jq -c '[.items[] | select((.tag // null) == null) | .id]'
not takes no argument, so select(not .x) parses but means "negate the whole input, then index that boolean", which fails at runtime with a confusing message. There is no prefix ! either. Pipe into not, or compare with == false.
Comparison and boolean operators
| Operator | Notes |
|---|---|
== != | deep structural equality, works on arrays and objects |
< <= > >= | total order across all types, never an error |
and or | short-circuit, lower precedence than comparison |
not | a filter, f | not |
jq defines a single total order over every type, so a comparison never fails:
null < false < true < numbers < strings < arrays < objects
jq -cn '1 < "a", [1] < [2], {a:1} == {a:1}, [1,2] == [1,2]' # true true true true
Sorting a mixed array therefore works, and null always sorts first. That is also why a missing key sorts to the top with sort_by.
has, in, contains, inside
| Filter | Asks |
|---|---|
has("k") | does this object have key k |
has(0) | does this array have index 0 |
"k" | in($obj) | the same question, arguments flipped |
contains(x) | does the input contain x, recursively |
inside(x) | the same question, arguments flipped |
jq -c '.meta | has("count"), has("nope")' # true false jq -c '.tags | has(0), has(9)' # true false jq -c '.meta as $m | "count" | in($m)' # true jq -c '.name | contains("pi")' # true, substring jq -c '.tags | contains(["web"])' # true, subset jq -c '.meta | contains({count: 3})' # true, submatch jq -c '.tags as $t | ["web"] | inside($t)' # true
in and inside take the container as an argument, so it is evaluated against the current input, not the original document. Bind it to a variable first, as above, or the path will resolve against the wrong thing.
has checks presence, .k != null checks value. A key present with a null value passes has and fails the second test.
any and all
Three arities each. The one-argument form is the one you want most of the time.
| Form | Meaning |
|---|---|
any / all | over an input array of values, truthiness |
any(cond) / all(cond) | over an input array, apply cond to each |
any(gen; cond) | over the outputs of gen, apply cond |
jq -c '[.items[].price] | any(. > 25)' # true jq -c '[.items[].price] | all(. > 5)' # true jq -c 'any(.items[]; .cat == "y")' # true jq -c 'all(.items[]; .price > 5)' # true jq -cn '[] | any' # false jq -cn '[] | all' # true, vacuously
Both short-circuit. any stops at the first true, all at the first false.
//, the alternative operator
a // b emits every truthy output of a, and only if there are none does it emit b.
jq -c '.nope // "dflt"' # "dflt" jq -cn 'null // 1' # 1 jq -cn 'false // 1' # 1 jq -cn '0 // 1' # 0, zero is truthy jq -cn '"" // 1' # "", empty string is truthy jq -cn 'empty // 9' # 9, no outputs at all jq -cn '(1, null, 2) // 9' # 1 then 2, the nulls are dropped
The last line is the behavior people miss. // is not a null-coalescing operator on a single value, it is a filter over a stream. .a? // "x" is the idiom for "this field, or a default, and do not error if the parent is the wrong type".
jq -c '.items[] | {id, tags: (.tags // [])}' # never null jq -c '[.. | .price? // empty]' # collect, ignore failures
try, catch, and isempty
jq -c '[.items[] | try (.price | tostring) catch "?"]' # ["10","20","30"] jq -cn '[(1, "a", 2) | try (. + 1) catch "skip"]' # [2,"skip",3] jq -cn '[(1, "a", 2) | (. + 1)?]' # [2,3] jq -c 'isempty(.items[] | select(.price > 99))' # true jq -c 'first(.items[] | select(.price > 15)) | .id' # 2
| Form | On error |
|---|---|
try f | emit nothing, same as f? |
try f catch g | run g with the error message as . |
f? | emit nothing, terser |
isempty(f) | true when f produces no output |
error("msg") | raise, exit 5 |
error | re-raise the input as an error |
try catches errors, not empty output. A filter that legitimately produces nothing still produces nothing, which is why isempty exists as a separate test.