jq β lightweight, flexible command-line JSON processor
- Basics
- Navigation
- Arrays
- Objects
- Filtering & Selection
- Transformation
- String Operations
- Math & Aggregation
- Conditionals
- Advanced
- Real-World Examples
# Pretty print JSON
cat file.json | jq '.'
# Compact output (single line)
jq -c '.' file.json
# Raw output (no quotes on strings)
jq -r '.name' file.json
# Read from string
echo '{"a":1}' | jq '.a'
# Null input (create JSON from scratch)
jq -n '{name: "test", value: 42}'# Get a field
jq '.name' # β "John"
# Nested field
jq '.address.city' # β "New York"
# Optional field (no error if missing)
jq '.missing?' # β null
# Multiple fields
jq '.name, .age' # β "John" \n 30
# Pipe through filters
jq '.address | .city' # β "New York"# First element
jq '.[0]' # β first item
# Last element
jq '.[-1]' # β last item
# Slice
jq '.[2:5]' # β elements 2,3,4
# All elements (iterate)
jq '.[]' # β each element
# Collect into array
jq '[.[] | .name]' # β ["a","b","c"]
# Length
jq 'length' # β 5
# First / Last
jq 'first' # β first element
jq 'last' # β last element
# Reverse
jq 'reverse' # β [3,2,1]
# Flatten
jq 'flatten' # β [1,2,3,4]
# Unique values
jq 'unique' # β deduplicated
# Sort
jq 'sort' # β sorted array
jq 'sort_by(.name)' # β sorted by field
# Range
jq -n '[range(5)]' # β [0,1,2,3,4]# Get all keys
jq 'keys' # β ["a","b","c"]
# Get all values
jq 'values' # β [1,2,3]
# Check if key exists
jq 'has("name")' # β true/false
# Add/update field
jq '. + {newfield: "value"}' # β merged object
jq '.name = "Jane"' # β update in place
# Delete field
jq 'del(.unwanted)' # β without field
# Rename key
jq '.newname = .oldname | del(.oldname)'
# Convert to entries
jq 'to_entries' # β [{key,value},...]
# Convert from entries
jq 'from_entries' # β {key: value, ...}
# Transform entries
jq 'with_entries(.value += 10)' # β modify all values# Select by condition
jq '.[] | select(.age > 21)'
# Select by field value
jq '.[] | select(.role == "admin")'
# Select non-null
jq '.[] | select(.email != null)'
# Select by type
jq '.. | numbers' # β all numbers
jq '.. | strings' # β all strings
jq '.. | booleans' # β all booleans
jq '.. | arrays' # β all arrays
jq '.. | objects' # β all objects
# Map with filter
jq 'map(select(.active == true))'
# Contains
jq 'select(.tags | contains(["admin"]))'
# Inside (inverse of contains)
jq 'select(.role | inside("admin user"))'
# Test with regex
jq 'select(.email | test("@gmail"))'
# Limit results
jq '.[:5]' # β first 5
jq 'limit(5; .[])' # β first 5 iterated# Map over array
jq 'map(.name)' # β extract field
jq 'map(. * 2)' # β transform each
# Create new object
jq '{username: .name, mail: .email}'
# Construct array
jq '[.users[].name]'
# Group by field
jq 'group_by(.category)' # β [[...],[...]]
# Index by field
jq 'INDEX(.id)' # β {id: obj, ...}
# Transpose
jq 'transpose' # β pivot array
# Add to array
jq '. += ["new"]' # β append
# Combine arrays
jq '. + ["extra"]' # β concatenate# Uppercase / Lowercase
jq '.name | ascii_upcase' # β "JOHN"
jq '.name | ascii_downcase' # β "john"
# String length
jq '.name | length' # β 4
# Split string
jq '.csv | split(",")' # β ["a","b","c"]
# Join array to string
jq '.tags | join(", ")' # β "a, b, c"
# String interpolation
jq '"Hello \(.name)!"' # β "Hello John!"
# Replace (regex)
jq '.text | gsub("old"; "new")'
# Trim whitespace
jq '.text | ltrimstr(" ") | rtrimstr(" ")'
# Starts/ends with
jq 'select(.url | startswith("https"))'
jq 'select(.file | endswith(".json"))'
# Match regex
jq '.text | match("[0-9]+")' # β match object
jq '.text | capture("(?<num>[0-9]+)")' # β named groups# Sum array
jq 'add' # β sum of array
jq '[.[].price] | add' # β sum field
# Average
jq 'add / length' # β average
# Min / Max
jq 'min' # β smallest
jq 'max' # β largest
jq 'min_by(.price)' # β object with min
jq 'max_by(.score)' # β object with max
# Count
jq 'length' # β count items
jq '[.[] | select(.active)] | length' # β count filtered
# Floor / Ceil / Round
jq '.price | floor'
jq '.price | ceil'
jq '.price | round'
# Absolute value
jq '.delta | fabs'
# Math operations
jq '.a + .b' # add
jq '.a - .b' # subtract
jq '.a * .b' # multiply
jq '.a / .b' # divide
jq '.a % .b' # modulo# If-then-else
jq 'if .age > 18 then "adult" else "minor" end'
# Alternative operator (default value)
jq '.missing // "default"' # β "default" if null
# Error suppression
jq '.field?' # β null if missing
# Not
jq 'select(.active | not)' # β where not active
# And / Or
jq 'select(.a and .b)'
jq 'select(.a or .b)'
# Empty (skip output)
jq 'if .hide then empty else . end'
# Try-catch
jq 'try .bad.path catch "error"'# Recursive descent
jq '.. | .id? // empty' # β all id fields
# Walk and transform
jq 'walk(if type == "string" then ascii_upcase else . end)'
# Reduce
jq 'reduce .[] as $x (0; . + $x)' # β sum
# Define variables
jq '.price as $p | .qty * $p'
# Define functions
jq 'def double: . * 2; [.[] | double]'
# Path expressions
jq 'path(.a.b)' # β ["a","b"]
jq 'getpath(["a","b"])' # β value at path
jq 'setpath(["a","b"]; 42)' # β set value
# Env variables
jq -n 'env.HOME' # β /home/user
# Input/Inputs (multiple JSON docs)
jq -s '.' # β slurp into array
jq -n '[inputs]' # β stream to array
# Format as CSV
jq -r '.[] | [.name, .age] | @csv'
# Format as TSV
jq -r '.[] | [.name, .age] | @tsv'
# Base64
jq '.data | @base64' # β encode
jq '.encoded | @base64d' # β decode
# URI encode
jq '.query | @uri'
# JSON stringify
jq '. | @json' # β escaped JSON string
# Dates
jq '.timestamp | todate' # β ISO date string
jq '"2024-01-01T00:00:00Z" | fromdateiso8601' # β epoch
jq 'now | todate' # β current time# Extract data from paginated API
curl -s 'https://api.example.com/users' | \
jq '.data[] | {id, name, email}'
# Get specific fields as CSV
curl -s 'https://api.example.com/users' | \
jq -r '.data[] | [.id, .name, .email] | @csv'# Parse JSON logs, filter errors
cat app.log | jq -c 'select(.level == "error")'
# Count errors by type
cat app.log | jq -s 'group_by(.error_type) |
map({type: .[0].error_type, count: length})'
# Get last 10 errors
cat app.log | jq -s '[ .[] | select(.level == "error") ] | .[-10:]'# Update config value
jq '.database.host = "newhost"' config.json > config.new.json
# Merge configs
jq -s '.[0] * .[1]' defaults.json overrides.json
# Remove sensitive fields before commit
jq 'del(.password, .api_key, .secret)' config.json# Convert array to lookup object
jq 'INDEX(.id)'
# Pivot data
jq 'group_by(.category) |
map({category: .[0].category, items: map(.name)})'
# Flatten nested structure
jq '[.. | objects | select(has("value")) | .value]'# Get pod names
kubectl get pods -o json | jq -r '.items[].metadata.name'
# Get container images
kubectl get pods -o json | jq -r '.items[].spec.containers[].image' | sort -u
# Docker inspect - get IP
docker inspect container_id | jq -r '.[0].NetworkSettings.IPAddress'# List EC2 instance IDs and states
aws ec2 describe-instances | \
jq -r '.Reservations[].Instances[] | [.InstanceId, .State.Name] | @tsv'
# Get S3 bucket sizes
aws s3api list-buckets | jq -r '.Buckets[].Name'| Flag | Description |
|---|---|
-r |
Raw output (no JSON quotes) |
-c |
Compact output |
-s |
Slurp (read all inputs into array) |
-n |
Null input (don't read stdin) |
-e |
Exit with error if result is null/false |
-S |
Sort keys |
-C |
Colorize output |
-M |
Monochrome output |
-f |
Read filter from file |
--arg name val |
Pass string variable |
--argjson name val |
Pass JSON variable |
--slurpfile var file |
Load file into variable |
| Task | Command |
|---|---|
| Pretty print | jq '.' |
| Get field | jq '.field' |
| Get nested | jq '.a.b.c' |
| Array element | jq '.[0]' |
| All elements | jq '.[]' |
| Filter | jq '.[] | select(.x > 5)' |
| Map | jq 'map(.field)' |
| Keys | jq 'keys' |
| Length | jq 'length' |
| Sort | jq 'sort_by(.field)' |
| Unique | jq 'unique' |
| Group | jq 'group_by(.field)' |
| Sum | jq 'add' |
| Default | jq '.x // "default"' |
| Delete | jq 'del(.field)' |
| Merge | jq '. + {new: 1}' |
| To CSV | jq -r '@csv' |
Version: jq 1.6+ | License: MIT | More: https://jqlang.github.io/jq/manual/