jq
Overview
jq is a command-line JSON processor. It slices, filters, maps, and transforms structured data the way sed/awk do for text lines. Prefer it for APIs, package.json, cloud CLIs, and any tool that emits JSON.
sudo apt install jqSyntax
jq [options] '<filter>' [file...]
… | jq [options] '<filter>'Common Options
| Option | Description |
|---|---|
. |
Identity — pretty-print JSON |
-r |
Raw string output (no JSON quotes) |
-c |
Compact (one value per line) |
-s |
Slurp: all inputs into one array |
-n |
Null input (build JSON from filter only) |
-e |
Exit non-zero if final result is false or null |
--arg name value |
Bind string variable $name |
--argjson name json |
Bind JSON-valued $name |
-S |
Sort object keys |
--stream |
Stream parse huge inputs (advanced) |
Key Use Cases
- Pretty-print API responses
- Extract fields for shell scripts
- Filter and map arrays of objects
- Build JSON safely from shell variables
- CI checks that required keys exist
Examples with Explanations
Pretty-print stdin
curl -sS https://api.github.com/repos/jqlang/jq | jq .Readable indentation for exploration. -sS shows curl errors without progress meter.
Extract a field
jq -r .name package.json
jq -r '.networkSettings.IPAddress // empty' inspect.json-r drops quotes so the value is shell-friendly. // empty suppresses nulls.
Map a list of objects to TSV
jq -r '.items[] | [.id, .name, .status] | @tsv' data.jsonTSV pipes cleanly into sort, column -t, or spreadsheets.
Filter array elements
jq '.[] | select(.status=="active" and .role=="admin")' users.json
jq '[.[] | select(.cpu > 80)] | length' metrics.jsonselect keeps matching objects; wrap in [] to recollect into an array.
Nested paths and optional keys
jq -r '.spec.containers[0].image // "missing"' pod.json
jq 'has("error")' response.jsonUse explicit paths; has is useful for boolean checks with -e.
Update / reshape objects
jq '.port = 8080 | .debug = false' config.json
jq '{name, version, scripts}' package.jsonFilters are expressions: assignment returns the modified object; object construction picks fields.
Flatten and walk arrays
jq -r '.. | objects | select(has("email")) | .email' big.json
jq -r '.[] | .tags[]?' items.json? avoids errors on missing paths; .. is recursive descent (powerful, easy to overuse).
Build JSON from shell (safe)
jq -n \
--arg user "$USER" \
--arg host "$(hostname -f 2>/dev/null || hostname)" \
--argjson n "$(nproc)" \
'{user:$user, host:$host, cpus:$n, ts: now|todateiso8601}'Always prefer --arg / --argjson over interpolating quotes by hand.
Merge two JSON files
jq -s '.[0] * .[1]' base.json overlay.json-s slurps files into an array; * deep-merges objects (right wins on conflicts).
Exit status for CI
jq -e '.version != null' package.json >/dev/null
jq -e '.[] | select(.severity=="critical") | halt_error(1)' findings.json-e fails on false/null final output; halt_error aborts mid-stream (jq 1.6+).
Compact logs / NDJSON
jq -c '.[]' array.json # one object per line
jq -c -r 'select(.level=="error")' app.ndjsonNewline-delimited JSON is ideal for tail -f pipelines.
Understanding Output
jq prints the filter result as JSON by default. Multiple results print one after another. Errors go to stderr. Parse failures are non-zero. With -r, strings lose JSON quoting; numbers/bools still print in a shell-friendly form.
Notes & Pitfalls
- Filters are programs — learn
.,[],|,select,map,keys,has,//.
- Never build JSON with string concatenation when secrets or user input are involved.
- Huge single JSON documents may need
--streamor preprocessing.
- YAML is not JSON; use
yq(or convert) for YAML.
- Unicode and locale: raw bytes in invalid UTF-8 can make
jqfail.