jq Is the SQL of JSON
Every API you talk to returns JSON. Every config file is JSON. Every log pipeline emits JSON. And yet most people still pipe curl output through grep and pray.
jq is the tool that makes JSON usable from the command line. Once you learn the basics, you will never go back.
Basics
Pretty-print some JSON:
curl -s https://api.github.com/users/torvalds | jq .
Extract a single field:
echo '{"name": "Linus", "repos": 5}' | jq .name
# "Linus"
Drop the quotes with -r:
echo '{"name": "Linus"}' | jq -r .name
# Linus
Arrays
Get the first element:
echo '[1, 2, 3]' | jq '.[0]'
# 1
Iterate over all elements:
echo '[{"name": "a"}, {"name": "b"}]' | jq '.[].name'
# "a"
# "b"
Filtering
This is where it gets powerful. Say you have a list of GitHub repos:
curl -s https://api.github.com/users/torvalds/repos | \
jq '[.[] | select(.stargazers_count > 1000)] | length'
That filters repos with more than 1000 stars and counts them.
Constructing Objects
You can reshape JSON on the fly:
curl -s https://api.github.com/users/torvalds/repos | \
jq '.[] | {name: .name, stars: .stargazers_count, lang: .language}'
This outputs a new object for each repo with only the fields you care about.
Real World: Parsing Docker
List container names and their memory usage:
docker stats --no-stream --format '{{json .}}' | \
jq -r '[.Name, .MemUsage] | @tsv'
Find containers using more than 100MB:
docker stats --no-stream --format '{{json .}}' | \
jq -r 'select(.MemPerc | gsub("%"; "") | tonumber > 1) | .Name'
Working With Nested Data
Given deeply nested JSON:
{
"data": {
"users": [
{"id": 1, "profile": {"email": "[email protected]"}},
{"id": 2, "profile": {"email": "[email protected]"}}
]
}
}
Extract all emails:
jq '[.data.users[].profile.email]' data.json
# ["[email protected]", "[email protected]"]
Combining With Other Tools
jq plays well with the rest of the Unix toolkit:
# Get all unique languages across repos
curl -s https://api.github.com/users/torvalds/repos | \
jq -r '.[].language // empty' | sort -u
# Convert JSON array to lines for xargs
echo '["file1.txt", "file2.txt"]' | jq -r '.[]' | xargs rm
# Merge multiple JSON files
jq -s 'add' file1.json file2.json > merged.json
The Cheat Sheet
| Pattern | What it does |
|---|---|
.field | Get field |
.[] | Iterate array |
select(cond) | Filter |
map(expr) | Transform array |
length | Count |
keys | Object keys |
to_entries | Object to key-value pairs |
@csv | Output as CSV |
@tsv | Output as TSV |
// | Default value |
jq has a learning curve, but it is one of those tools where the investment pays off within a week. Every time you find yourself writing a Python script just to parse some JSON, remember that jq probably does it in one line.