jq Cheatsheet
Strings and Formats
Use this jq reference while you build software engineering projects, review code, or refresh the syntax you reach for most.
Splitting and joining
split has two arities and they are different functions. One argument is a literal
separator, two arguments is a regex with flags.
jq -cn '"a,b,c" | split(",")' # ["a","b","c"] jq -cn '"a,b,c" | split(",") | join("-")'# "a-b-c" jq -cn '"a1b2c" | split("[0-9]"; null)' # ["a","b","c"], regex form jq -cn '"a1b2c" | [splits("[0-9]")]' # ["a","b","c"], as a stream jq -cn '"abc" | split("")' # ["a","b","c"] jq -cn '["a",1,null] | join("-")' # "a-1-", numbers stringify, null is ""
| Filter | Separator | Returns |
|---|---|---|
split(str) | literal | an array |
split(re; flags) | regex | an array |
splits(re) / splits(re; flags) | regex | a stream |
join(str) | — | a string, null becomes "" |
explode / implode | — | array of codepoints, and back |
trimstr(s) | — | strips s from both ends, jq 1.7.1+ |
join errors on an array containing an object or an array. Only strings, numbers,
booleans, and null are joinable.
Prefix, suffix, trim, case
jq -cn '"prefix-x" | startswith("pre"), endswith("x")' # true true jq -cn '"prefix-x" | ltrimstr("prefix-")' # "x" jq -cn '"x.json" | rtrimstr(".json")' # "x" jq -cn '"abc" | ltrimstr("zzz")' # "abc", no match is a no-op jq -cn '" x " | trim, ltrim, rtrim' # "x" "x " " x" jq -cn '"xax" | trimstr("x")' # "a", both ends jq -cn '"Hello" | ascii_downcase, ascii_upcase' # "hello" "HELLO" jq -cn '"abc" | test("^a"), (. | contains("bc"))' # true true jq -cn '"abcabc" | index("b"), rindex("b"), indices("b")' # 1 4 [1,4]
- trim, ltrim, and rtrim were added in jq 1.7.1. On older jq use
sub("^\\s+";"") and sub("\\s+$";"").
- ltrimstr and rtrimstr strip a literal string, once, not a character set.
"aaab" | ltrimstr("a") is "aab".
- In jq 1.8 these raise on a non-string input rather than passing it through.
1 | ltrimstr("a") is an error, so guard with if type == "string".
- ascii_downcase only touches A-Z. It does not fold É.
Regex: test, match, capture, scan, sub
jq uses Oniguruma, which is close to PCRE. Named groups are (?<name>...).
| Filter | Returns |
|---|---|
test(re) / test(re; flags) | a boolean |
match(re; flags) | an object per match, with offset, length, string, captures |
capture(re; flags) | an object of the named groups only |
scan(re) | each match as a string, or an array when the regex has groups |
sub(re; str) | the first match replaced |
gsub(re; str) | every match replaced |
sub(re; str; flags) | same with flags |
jq -cn '"foo123" | test("[0-9]+"), test("FOO"; "i")' # true true jq -cn '"foo123bar45" | [scan("[0-9]+")]' # ["123","45"] jq -cn '"2024-01-02" | capture("(?<y>[0-9]{4})-(?<m>[0-9]{2})")' # {"y":"2024","m":"01"} jq -cn '"foo123" | match("([a-z]+)([0-9]+)") | {offset, length, captures: [.captures[].string]}' # {"offset":0,"length":6,"captures":["foo","123"]} jq -cn '"a1b2" | [match("[0-9]"; "g").offset]' # [1,3] jq -cn '"a-b-c" | sub("-";"+"), gsub("-";"+")' # "a+b-c" "a+b+c" jq -cn '"foo123" | sub("(?<n>[0-9]+)"; "[\(.n)]")' # "foo[123]"
The replacement in sub and gsub is a jq string, so \(...) interpolation
works and named captures are in scope as fields of .. That is the only way to
reference a group in the replacement, there is no \1.
The flag letters are not PCRE's. This trips up everyone:
| Flag | Means in jq |
|---|---|
g | global, all matches |
i | case insensitive |
x | extended, whitespace and # comments ignored |
n | ignore empty matches |
m | . matches newline, PCRE's s |
s | single line, ^→\A and $→\Z |
p | both s and m |
l | prefer the longest match |
jq -cn '"a\nb" | test("a.b"), test("a.b"; "m")' # false then TRUE jq -cn '"a\nb" | test("^b")' # false, ^ is string start jq -cn '"a b" | test("a b"; "x")' # false, x ate the space
Under x, write a literal space as \s or [ ].
Interpolation and @ formats
"\(expr)" embeds any jq expression in a string. An @format before a string
literal applies that format to only the interpolated parts, which is how you
build safe shell commands and URLs.
jq -rn '{a:1} | "a is \(.a) and \(.a + 1)"' # a is 1 and 2 jq -rn '@base64 "v=\("hi")"' # v=aGk= jq -r '.items[] | "\(.id): \(.name) at \(.price)"' data.json jq -rn '@uri "https://x.dev/s?q=\("a b&c")"' # ...?q=a%20b%26c jq -rn '@sh "rm -- \("my file.txt")"' # rm -- 'my file.txt'
| Format | Turns a value into |
|---|---|
@text | tostring, the default |
@json | tojson, a JSON-encoded string |
@csv | one CSV row from an array, strings quoted, null empty |
@tsv | one TSV row, tabs and newlines escaped as \t \n |
@html | <, >, &, ', " escaped |
@uri | percent-encoded, reserved characters included |
@sh | shell-quoted, an array becomes space-separated words |
@base64 / @base64d | encode / decode |
jq -rn '[1,"a,b",null] | @csv' # 1,"a,b", jq -rn '[1,"a\tb",null] | @tsv' # 1<TAB>a\tb<TAB> jq -rn '"<a>" | @html' # <a> jq -rn '"it'"'"'s" | @sh' # 'it'\''s' jq -rn '"hi" | @base64' # aGk= jq -rn '"aGk=" | @base64d' # hi jq -rn '{a:1} | @json' # {"a":1}
@csv and @tsv require an array of scalars and reject nested containers. Pair them
with -r, or the row comes out as a quoted JSON string.
Numbers and JSON text as strings
jq -cn '1 | tostring' # "1" jq -cn '"2" | tonumber' # 2 jq -cn '"x" | tonumber' # error, exit 5 jq -cn '"x" | (tonumber? // null)' # null, the safe parse jq -cn '{a:1} | tojson' # "{\"a\":1}" jq -cn '"{\"a\":1}" | fromjson' # {"a":1} jq -rn '[1,2] | tostring' # [1,2], same as tojson on a container jq -cn '"1e3" | tonumber' # 1E+3, the literal is preserved, not normalized jq -cn '3.14159 | tostring' # "3.14159"
- tostring on a container is tojson. On a string it is a no-op, which is why
@text never double-quotes.
- Parsing embedded JSON is fromjson, and it is the right move for a log field that
holds a JSON blob as a string.
- Large integers keep their literal text when they pass through untouched, but any
arithmetic converts them to IEEE 754 doubles and loses precision past 2⁵³.
echo '{"id":12345678901234567890}' | jq -c '.' # preserved verbatim echo '{"id":12345678901234567890}' | jq -c '.id + 0' # 12345678901234567000