jq is grep for JSON — a filter language that turns API responses and config files into exactly the fragment you wanted. If you have ever piped pretty-printed JSON into less and scrolled, jq is the end of that habit.

Reading JSON #

. is the identity filter; field access chains from it:

Pull fields out of an API response
$ curl -s https://aospix.com/api/posts | jq '.posts[0].slug'
$ curl -s https://aospix.com/api/posts | jq -r '.posts[].title'

-r outputs raw strings without quotes, -r and arrays iterate naturally. That second line is a complete API report: every post title, one per line.

The filters that matter #

FilterEffect
.fieldOne field
.items[]Iterate an array
`.[] \.name`Map over elements
select(.ok)Keep matching items
lengthCount
keysList object keys
{n: .name}Build new objects

Selection is where jq starts feeling like a query language — the JSON equivalent of grep:

Filter API results by a field value
$ jq '.posts[] | select(.status == "published") | .slug' data.json

Building output #

jq does not just extract; it reshapes. Turning JSON into CSV is a two-filter move:

JSON array to comma-separated columns
$ jq -r '.rows[] | [.name, .size] | @csv' export.json

And summarising — counts by a key — replaces an entire reporting script:

Count posts per kicker
$ jq -r '.posts[] | .kicker' data.json | sort | uniq -c | sort -rn

Note the hand-off at the end: jq produced clean lines, then sort and uniq counted them. Pipes compose even across paradigms.

For the HTTP side that feeds jq, see curl; for the wider pipeline discipline, unix pipes in practice. The terminal notes series continues from here.