Intermediate · 12 min · practise every command in the built-in terminal

jq — Working with JSON

APIs, cloud tools and config files speak JSON. grep and awk see it as lines of text; jq understands it.

It isn't installed on a fresh Debian:

sudo apt install jq

Your server inventory for this lesson is in ~/json/servers.json.

Pretty-print and pick

jq . ~/json/servers.json                 # the whole file, indented
jq .updated ~/json/servers.json          # one field
jq '.servers[0]' ~/json/servers.json     # the first server
jq '.servers[0].ip' ~/json/servers.json  # a field of it

. is "the input". .servers takes a field, [0] an element of an array ([-1] is the last).

Always put the filter in single quotes — [, | and " mean something to the shell too.

Every element: .[]

jq '.servers[].name' ~/json/servers.json      # "web01" "web02" ...
jq -r '.servers[].name' ~/json/servers.json   # -r: raw text, no quotes

-r is what you want when the output goes on to grep, while read or a file.

Pipes inside jq

| passes each result on, like in the shell:

jq '.servers | length' ~/json/servers.json                       # how many
jq '.servers[] | select(.status == "stopped") | .name' ~/json/servers.json
jq '[.servers[].ram_gb] | add' ~/json/servers.json               # total RAM
  • select(CONDITION) keeps only what matches — ==, !=, >, and, or work as you'd expect
  • [ ... ] collects results into an array; add sums it, length counts it

Your own shape

jq '.servers[] | {name, ip}' ~/json/servers.json        # just these fields
jq -c '.servers[] | {name, ram: .ram_gb}' ~/json/servers.json   # -c: one line each
jq -r '.servers[] | "\(.name) has \(.ram_gb) GB"' ~/json/servers.json

\( … ) puts a value into a string.

Into a spreadsheet: @csv

jq -r '.servers[] | [.name, .ip, .status] | @csv' ~/json/servers.json
"web01","10.0.0.11","running"
"web02","10.0.0.12","stopped"

Straight from an API

curl -s + jq is the everyday pair:

curl -s https://api.example.com/servers | jq '.servers[] | select(.status != "running") | .name'
FilterDoes
.a.bfield b of field a
.[0], .[-1]first / last element
.[]every element
select(...)keep what matches
map(...)change every element of an array
length, add, keyscount, sum, field names
sort_by(.x), group_by(.x)order, group

💡 jq -r + @csv turns any JSON into something sort, awk or a spreadsheet can read.

Practice tasks

  1. Install jq
  2. Show servers.json nicely indented
  3. List just the server names, without quotes
  4. Find the server that is stopped
  5. Add up the RAM of all servers
  6. Print each server's name and IP as CSV

Commands in this lesson

Text Processing