jq --arg u "$USER" '.[]|select(.name==$u)'a shell variable into the filter
Overview
jq is like grep/sed, but for JSON. Indispensable when working with
APIs (curl) and config files. It understands structure, not just text.
bash
echo '{"name":"web","port":80}' | jq . # pretty-print
echo '{"name":"web","port":80}' | jq '.name' # → "web"
curl -s https://api/x | jq '.items[0].id' # a field from an API response
Options
8
-r strips the quotes from a string result — without it, a script gets the
JSON literal "value" instead of value. --arg/--argjson are the only
safe way to pass a shell variable into a filter: pasting a variable straight
into the filter text breaks on quotes and special characters. -s (slurp)
is needed when the input is a stream of several JSON objects that must be
processed as a single array.
Option
What it does
Example
-r--raw-output
Raw string output — without JSON quotes, convenient for scripts.
jq -r '.name'
--argname value
Pass a shell variable's value into the filter as a string.
jq --arg u "$USER" '.users[]|select(.name==$u)'
-c--compact-output
Compact output — one JSON object per line, no indentation.
jq -c '.'
-s--slurp
Slurp the whole input stream into a single array before processing.
jq -s '.'
--argjsonname value
Pass a value into the filter as JSON (number, object, array).
jq --argjson n 5 '.items[:$n]'
-n--null-input
Do not read input — useful for generating JSON from scratch.
jq -n '{a:1}'
-e--exit-status
Exit status 1 if the result is false or null; useful in scripts.
jq -e '.ok'
-C--color-output
Always colorize output, even when it is not going to a terminal.
jq -C . file.json
Nothing found. Try a shorter query.
Recipes
2
Filters
bash
jq '.' # the whole JSON, pretty-printed
jq '.key' # a field
jq '.a.b.c' # a nested field
jq '.key // "default"' # the value, or a default if null/missing
jq '.items[]' # every array element
jq '.items[0]' # the first element
jq '.items[-1]' # the last element
jq '.items | length' # array length
jq 'keys' # the keys
jq 'has("name")' # does the key exist
jq '.items[] | .name' # each element's name
jq '.items[] | select(.active)' # filter by a condition
jq '.items[] | select(.cpu > 80)' # a numeric condition
jq '.items | map(.name)' # an array of names
jq '.items | group_by(.role)' # group them
jq -r '.name' # -r: "raw" output (no quotes) — for scripts
Examples and assembly
bash
# every service's IP from an API (as plain lines for a script)
curl -s https://api/services | jq -r '.[].ip'
# filter and build a table (TSV)
curl -s https://api/users | jq -r '.[] | select(.role=="admin") | [.id,.name] | @tsv'
# build a CSV with a header
jq -r '["id","name"], (.[] | [.id,.name]) | @csv' users.json
# substitute a shell variable into the filter (safely)
jq --arg u "$USER" '.users[] | select(.name==$u)' data.json
# build a new object
jq '{name: .name, port: .ports[0]}' svc.json
# edit a JSON file "in place" (sponge from moreutils)
jq '.version="2"' conf.json | sponge conf.json
Troubleshooting
4
SymptomCause and fix
jq: error: Cannot index ...
The structure isn't what you expect. Run jq . first (look at the shape),
then build around it. Is the field an object or an array? .items[] for an
array, .items.x for an object.
There are extra quotes in the output
jq prints strings with quotes. If you need raw text (for scripts/loops), use
jq -r.
Invalid JSON on the input
jq fails on non-JSON. Check that the previous command actually produces
JSON (not HTML or an error): curl -s URL | head. For a "stream" of JSON
objects, use jq -s (slurp) or --stream.
You need to substitute a shell variable
Don't paste it into the filter text — use --arg name val (a string) or
--argjson (a number/JSON), and reference it inside as $name.
See also
curl — HTTP/HTTPS requests from the CLI — debugging APIs and web services, headers, methods.
text-tools — Processing text and streams — sorting, uniqueness, columns, counting.