jq Cheatsheet
Output Flags
Use this jq reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
Input flags
These change what jq reads, before any filter runs.
| Flag | Reads |
|---|---|
-n, --null-input | nothing, . is null. Use input/inputs to pull explicitly |
-R, --raw-input | each line as a JSON string instead of parsing JSON |
-s, --slurp | every input into one array, then run the filter once |
-f file, --from-file | the filter itself from a file |
--stream | the input as a stream of [path, value] events |
--seq | input and output as RFC 7464 json-seq, with 0x1e separators |
-L dir | a module search path for import / include |
jq -n '1 + 1' # 2, no input read jq -cn '[inputs]' multi.json # [{"a":1},{"a":2}] jq -c -s '.' multi.json # [{"a":1},{"a":2}], same result jq -c -s 'map(.a) | add' multi.json # 3 printf 'a\nb\n' | jq -R '.' # "a" then "b" printf 'a\nb\n' | jq -Rn -c '[inputs]' # ["a","b"] printf 'a\nb\n' | jq -Rs -c 'split("\n")' # ["a","b",""], -s keeps the last newline jq -f prog.jq data.json jq -c --stream '.' <<< '{"a":[1,2]}' # [["a",0],1] [["a",1],2] [["a",1]] [["a"]]
- Without -n, a leading input consumes the second value, because the first is
already ..
- -s loads everything into memory. For a huge NDJSON file, iterate the default
one-value-at-a-time stream and let jq stay constant-memory.
- --seq applies to input as well as output, so piping ordinary JSON into a
--seq invocation is a parse error, not a formatting choice.
Output shape
| Flag | Effect |
|---|---|
-c, --compact-output | one line per value, no indentation |
--tab | indent with tabs |
--indent n | indent with n spaces, 0 for newline-separated with no indent, max 7 |
-S, --sort-keys | sort object keys on output, recursively |
-a, --ascii-output | escape every non-ASCII character as \uXXXX |
-C / -M | force color on / off |
--unbuffered | flush after each value, for a live pipe |
jq -c '.meta' data.json # {"count":3} jq --tab '.meta' data.json # tab-indented jq --indent 0 '.meta' data.json # newline-separated, zero indent jq -cS '.' data.json # keys sorted, one line, good for diffing echo '{"s":"café"}' | jq -a '.s' # "café" tail -f app.log | jq --unbuffered -c 'select(.level == "error")'
jq -cS on both sides is the standard way to diff two JSON documents, because it
removes formatting and key-order noise:
diff <(jq -cS . a.json) <(jq -cS . b.json)
diff <(jq -S . a.json) <(jq -S . b.json) # pretty, easier to read the hunksString output: -r, -j, --raw-output0
By default a string output is a JSON string, with quotes and escapes. That is almost never what you want when feeding another shell command.
| Flag | Strings come out |
|---|---|
| none | quoted and escaped, "api" |
-r, --raw-output | bare, one per line, api |
-j, --join-output | bare, no trailing newline, implies -r |
--raw-output0 | bare, NUL-terminated, implies -r |
jq '.name' data.json # "api" jq -r '.name' data.json # api jq -j '.tags[]' data.json # webprod, no separator at all jq --raw-output0 '.tags[]' data.json | xargs -0 -n1 echo
-r only affects values that are strings. A number or an object prints the same
either way, so -r is safe to leave on.
--raw-output0 plus xargs -0 is the only safe way to hand jq output to another
command when a value could contain a space, a newline, or a quote:
# safe jq --raw-output0 '.items[].name' data.json | xargs -0 -n1 printf '%s\n' # unsafe, breaks on any name containing whitespace jq -r '.items[].name' data.json | xargs -n1 printf '%s\n'
Exit status and -e
| Code | Meaning |
|---|---|
| 0 | ran fine |
| 1 | with -e, the last output was false or null |
| 2 | usage or system error, including a file that cannot be read |
| 3 | the jq program failed to compile |
| 4 | with -e, the program produced no output at all |
| 5 | a runtime error, or an explicit error / halt_error |
jq -e '.name' data.json >/dev/null; echo $? # 0 jq -e '.nope' data.json >/dev/null; echo $? # 1, output was null jq -e 'false' data.json >/dev/null; echo $? # 1 jq -e 'empty' data.json >/dev/null; echo $? # 4, no output jq 'false' data.json >/dev/null; echo $? # 0, WITHOUT -e jq '.a[0]' <<< '{"a":1}' >/dev/null 2>&1; echo $? # 5, runtime error jq '.[' data.json >/dev/null 2>&1; echo $? # 3, compile error
Without -e, a filter that outputs false still exits 0. That is the single most
common bug when jq is used as a shell test.
# right if jq -e '.items | length > 0' data.json >/dev/null; then echo "has items"; fi # wrong, always true if jq '.items | length > 0' data.json >/dev/null; then echo "has items"; fi # distinguish "false" from "no output" jq -e '.items[] | select(.price > 99)' data.json >/dev/null case $? in 0) echo found;; 4) echo none;; *) echo error;; esac
halt_error(n) sets an arbitrary code, which is how a jq program signals a specific
failure to a script:
jq -rn '"missing required field\n" | halt_error(3)'; echo $? # 3 jq -e 'if .name then true else "no name\n" | halt_error(2) end' data.json
Flags worth setting by habit
# reading a document you do not know jq --tab -S '.' data.json | head -40 # a value into a shell variable name=$(jq -r '.name' data.json) # an array into a bash array, whitespace safe mapfile -t -d '' names < <(jq --raw-output0 '.items[].name' data.json) # NDJSON in, NDJSON out, constant memory jq -c 'select(.level == "error") | {t: .ts, m: .msg}' app.ndjson # a shell test jq -e '.items | all(.price > 0)' data.json >/dev/null || echo "bad prices" # a stable snapshot for a diff or a checksum jq -S . config.json | shasum -a 256
| Combination | For |
|---|---|
-r | any string you will pass to another command |
-c | NDJSON, while read loops, one line per record |
-cS | diffing two documents |
-e | using jq as a condition |
-n + --argjson | building JSON from shell values with no input document |
-Rn 'inputs' | reading plain text line by line |
--raw-output0 + xargs -0 | filenames and anything that may contain whitespace |
# build a JSON body from shell values, no input file jq -n --arg name "$NAME" --argjson n 3 '{name: $name, count: $n}'