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

PatternWhat it does
.fieldGet field
.[]Iterate array
select(cond)Filter
map(expr)Transform array
lengthCount
keysObject keys
to_entriesObject to key-value pairs
@csvOutput as CSV
@tsvOutput 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.

← all articles wleeaf.dev →