Cheat sheet · No. XII

jq.

jq is a pipeline language for JSON: every filter takes a value and emits zero or more values, and | feeds one filter into the next — exactly like the shell it lives in.

Printable One A4 page
PLATE — jqFIG. XII {"items": [{"name": …},{"name": …}]}.items[]"ada" jq '.items[].name' pipe in, field outone page, pinned to the wall.
The reference
SELECTORS
.
The whole input (pretty-prints)
.name
Field
.user.address.city
Nested path
.[0]
Array index
.[]
Iterate — one output per element
.field?
No error if missing
.["odd key"]
Keys that aren't identifiers
PIPES & FILTERS
a | b
Feed a's output into b
select(.age > 21)
Keep or drop a value
map(.price)
Rewrite each array element
map(select(.active))
Filter an array in place
keys length
Object keys / size of anything
has("id")
Key present?
..
Recursive descent — every value
RESHAPE
sort_by(.date)
Sort an array
group_by(.status)
Array of arrays, grouped
unique_by(.id)
Dedup on a key
min_by(.x) max_by(.x)
Extremes
add
Sum numbers / merge objects
to_entries
Object → [{key, value}] pairs
{id, name}
Pick fields into a new object
STRINGS & OUTPUT
"\(.first) \(.last)"
String interpolation
join(", ") split(",")
Array ↔ string
tostring tonumber
Casts
@csv @tsv
Array of scalars → CSV/TSV row
@json
Value → JSON string
@base64 @base64d
Encode / decode
FLAGS
-r
Raw strings, no quotes — for shell pipelines
-c
Compact, one JSON value per line
-s
Slurp: wrap all inputs into one array
-n
No input — generate from scratch
--arg k v
Pass a shell value in as $k (safely)
-e
Exit 1 on null/false — for scripts
-S
Sort object keys (stable diffs)
ONE-LINERS
jq -r '.items[].name' f.json
Extract one field per line
jq '[.[] | select(.active)]' f.json
Filter an array, keep it an array
jq -r '.[] | [.id, .name] | @csv' f.json
JSON → CSV
jq 'group_by(.status) | map({(.[0].status): length})' f.json
Count by field
curl -s api.example.com/users | jq '.[0]'
Peek at the first record
Field notes
Reach for -r in pipelines

By default jq prints JSON, quotes included. -r emits raw strings, which is what xargs, while read, and every other shell tool expects.

select filters, map transforms

select(cond) passes a value through or drops it; map(f) rewrites each element. Most one-liners are map(select(…)): keep some, reshape what survives.

Pass shell values with --arg

jq --arg u "$USER" '.[] | select(.owner == $u)' avoids quoting bugs and injection. Never splice shell variables into the filter text itself.

.[] fans out

A filter containing .[] emits one result per element, not an array. Wrap the whole expression in [ … ] when you need an array back.

Tip: hit ⌘P / Ctrl-P to save this single page as a PDF or print it for the wall.

Found this useful?