jq spiekbriefje: 30 praktische patronen voor JSON op de commandoregel
Je geeft kubectl get pods -o json door aan less, en de terminal bevriest op een muur van twee megabyte JSON. Je wil alleen de naam van elke pod met de fase Running. jq doet dat in drie tekens filtersyntaxis — als je de vocabulaire kent.
Dit is geen syntaxisreferentie. Het zijn 30 patronen die je daadwerkelijk typt, gegroepeerd op de taak die je probeert uit te voeren: toegang, filteren, transformeren, aggregeren, formatteren en samenvoegen met echte tools als kubectl, aws en docker.
Wanneer gebruik je jq, een browser-formatter of code?
jq is niet altijd het juiste antwoord. De drie eerlijke keuzes zien er zo uit:
| Situatie | Beste tool | Waarom |
|---|---|---|
| Eén API-response, syntaxismarkering en regelnummers bij fouten nodig | Browser JSON Formatter | Visueel overzicht, geen setup, privé in de browser |
| Shell-pipeline, logverwerking, CI-script, externe server | jq | Samen te stellen, te scripten, geen GUI-afhankelijkheid |
| Bedrijfslogica, unit-tests, complexe vertakkingen | Taalcode (JS / Python) | Echte debugger, typen, bibliotheken |
Kies jq wanneer de taak in een shell-pipeline past — alles anders is waarschijnlijk ergens anders gemakkelijker.
Installatie en je eerste pipeline
jq wordt geleverd als één binary op elk groot platform:
# macOS
brew install jq
# Debian / Ubuntu
sudo apt install jq
# Windows (winget)
winget install jqlang.jq
Een eerste pipeline, met de identiteitsfilter:
curl -s https://api.github.com/users/octocat | jq .
De .-filter neemt de invoer en geeft die ongewijzigd, netjes opgemaakt terug. Dat alleen al vervangt de meeste “even dit JSON-bestand openen in een editor”-momenten.
Vijf vlaggen dekken 90% van het dagelijkse gebruik:
| Vlag | Doel |
|---|---|
-r | Ruwe uitvoer — verwijder aanhalingstekens rondom string-resultaten |
-c | Compact — één JSON-waarde per regel (NDJSON) |
-s | Slurp — lees alle invoer in één array |
-R | Ruwe invoer — lees regels als strings in plaats van JSON |
-n | Null-invoer — lees geen stdin, gebruik null als invoer |
Het kernmodel: filters en pipes
Een filter neemt één JSON-waarde als invoer en produceert nul of meer JSON-waarden als uitvoer. Filters combineer je met een pipe |, die elke uitvoer van de linker filter doorgeeft als invoer aan de rechter filter. Dit is hetzelfde model als shell-pipes, maar dan met JSON-waarden die stromen in plaats van bytes.
# . — identiteit
echo '{"name":"Alice"}' | jq '.'
# .key — veldtoegang
echo '{"name":"Alice"}' | jq '.name'
# .key.sub — diep pad
echo '{"user":{"email":"a@x.com"}}' | jq '.user.email'
# .[] — itereer over array-elementen (produceert meerdere uitvoerwaarden)
echo '[{"id":1},{"id":2}]' | jq '.[] | .id'
# Pipe-samenstelling: elke uitvoer van .items[] wordt doorgegeven aan .name
echo '{"items":[{"name":"a"},{"name":"b"}]}' | jq '.items[] | .name'
Dat is de volledige grammatica. De 30 patronen hieronder zijn combinaties van deze bouwblokken.
30 patronen die je daadwerkelijk gebruikt
Elk patroon toont invoer-JSON, de opdracht en de uitvoer. Kopieer een patroon naar je terminal.
Toegang en extractie (patronen 1–5)
Patroon 1 — Veilige toegang met ?
Toegang tot een veld dat mogelijk niet bestaat, zonder foutmelding:
echo '{"name":"Alice"}' | jq '.address?.city?'
# Output: null
De ? onderdrukt fouten bij ontbrekende sleutels. Zonder ? geeft .address.city een typefout als .address ontbreekt.
Patroon 2 — Toegang via diep pad
echo '{"user":{"profile":{"email":"a@x.com"}}}' | jq '.user.profile.email'
# Output: "a@x.com"
Patroon 3 — Array-slicing
echo '[10,20,30,40,50]' | jq '.[1:3]'
# Output: [20, 30]
echo '[10,20,30,40,50]' | jq '.[-1]'
# Output: 50
Negatieve indices tellen van achteren. Slices gebruiken half-open intervallen, net als Python.
Patroon 4 — Recursieve afdaling om elke overeenkomende sleutel te vinden
echo '{"a":{"name":"x"},"b":[{"name":"y"},{"id":1}]}' | jq '.. | .name? | select(. != null)'
# Output: "x"
# "y"
.. doorloopt elke waarde in de boom. Gecombineerd met .name? en select extraheert het elk name-veld ongeacht de diepte — onmisbaar bij het verkennen van onbekende JSON-schema’s.
Patroon 5 — Alle sleutels van een object opvragen
echo '{"zebra":1,"apple":2,"mango":3}' | jq 'keys'
# Output: ["apple", "mango", "zebra"]
echo '{"zebra":1,"apple":2,"mango":3}' | jq 'keys_unsorted'
# Output: ["zebra", "apple", "mango"]
keys sorteert alfabetisch; keys_unsorted bewaart de invoegvolgorde.
Filteren (patronen 6–10)
Patroon 6 — Een array filteren op voorwaarde
echo '[{"age":20},{"age":30},{"age":40}]' | jq 'map(select(.age > 25))'
# Output: [{"age":30},{"age":40}]
map(f) past f toe op elk element; select(cond) behoudt alleen elementen waarvoor de voorwaarde geldt.
Patroon 7 — Prefix-matching op strings
echo '[{"name":"api-gateway"},{"name":"web-ui"},{"name":"api-auth"}]' \
| jq '.[] | select(.name | startswith("api"))'
# Output: {"name":"api-gateway"}
# {"name":"api-auth"}
Ook handig: endswith("..."), contains("..."), test("^regex$").
Patroon 8 — Gecombineerde voorwaarden
echo '[{"type":"A","count":5},{"type":"A","count":15},{"type":"B","count":20}]' \
| jq '.[] | select(.type == "A" and .count > 10)'
# Output: {"type":"A","count":15}
and, or, not werken zoals je verwacht.
Patroon 9 — Gevoelige velden verwijderen
echo '{"user":"alice","password":"s3cret","token":"abc"}' | jq 'del(.password, .token)'
# Output: {"user":"alice"}
del() accepteert meerdere paden en werkt veilig als een pad ontbreekt.
Patroon 10 — Dedupliceren op veld
echo '[{"id":1,"v":"a"},{"id":2,"v":"b"},{"id":1,"v":"a2"}]' | jq 'unique_by(.id)'
# Output: [{"id":1,"v":"a"},{"id":2,"v":"b"}]
unique dedupliceert hele waarden; unique_by(f) dedupliceert op het resultaat van een filter.
Transformeren (patronen 11–15)
Patroon 11 — Velden hernoemen
echo '[{"first_name":"Alice","age":30}]' | jq 'map({name: .first_name, age})'
# Output: [{"name":"Alice","age":30}]
De afkorting {age} is gelijk aan {age: .age}.
Patroon 12 — Een berekend veld toevoegen met string-interpolatie
echo '[{"first":"Alice","last":"Chen"}]' \
| jq 'map(. + {fullName: "\(.first) \(.last)"})'
# Output: [{"first":"Alice","last":"Chen","fullName":"Alice Chen"}]
\(expr) evalueert expr en voegt de waarde in de string in.
Patroon 13 — Geneste arrays afvlakken
echo '[{"tags":["a","b"]},{"tags":["c"]}]' | jq '[.[] | .tags[]]'
# Output: ["a","b","c"]
echo '[[1,2],[3,[4,5]]]' | jq 'flatten'
# Output: [1,2,3,4,5]
flatten accepteert een optioneel diepte-argument: flatten(1) verwijdert slechts één niveau.
Patroon 14 — Object naar array en terug
echo '{"a":1,"b":2}' | jq 'to_entries'
# Output: [{"key":"a","value":1},{"key":"b","value":2}]
echo '[{"key":"a","value":1},{"key":"b","value":2}]' | jq 'from_entries'
# Output: {"a":1,"b":2}
Dit paar maakt transformaties mogelijk waarbij je over objectsleutels itereert — iets wat je met puntpadsyntaxis niet direct kunt.
Patroon 15 — Twee objecten diep samenvoegen
echo '{"a":{"x":1},"b":2}' | jq '. * {a:{y:9}, c:3}'
# Output: {"a":{"x":1,"y":9},"b":2,"c":3}
De *-operator voegt diep samen. Voor een oppervlakkige samenvoeging gebruik je + (rechter kant wint).
Aggregeren (patronen 16–20)
Patroon 16 — Lengte van arrays, objecten en strings
echo '[1,2,3,4]' | jq 'length' # 4
echo '{"a":1,"b":2}' | jq 'length' # 2
echo '"hello"' | jq 'length' # 5
Patroon 17 — Een veld optellen
echo '[{"price":10},{"price":25},{"price":5}]' | jq '[.[].price] | add'
# Output: 40
add telt getallen op, voegt strings samen of arrays bijeen — afhankelijk van het invoertype.
Patroon 18 — Groeperen op veld
echo '[{"cat":"A","n":1},{"cat":"B","n":2},{"cat":"A","n":3}]' | jq 'group_by(.cat)'
# Output: [[{"cat":"A","n":1},{"cat":"A","n":3}],[{"cat":"B","n":2}]]
Elke groep wordt een binnenste array. Combineer met map om per groep te aggregeren.
Patroon 19 — Aflopend sorteren
echo '[{"date":"2026-01-03"},{"date":"2026-01-01"},{"date":"2026-01-02"}]' \
| jq 'sort_by(.date) | reverse'
# Output: [{"date":"2026-01-03"},{"date":"2026-01-02"},{"date":"2026-01-01"}]
ISO 8601-datumstrings sorteren correct als strings. Voor andere formaten moet je ze eerst verwerken — de Unix-timestamp-gids behandelt epoch-seconden, milliseconden en tijdzoneconversie uitgebreid.
Patroon 20 — Maximum of minimum op veld
echo '[{"name":"a","rating":4.1},{"name":"b","rating":4.8},{"name":"c","rating":3.9}]' \
| jq 'max_by(.rating)'
# Output: {"name":"b","rating":4.8}
min_by en max_by geven één element terug. Voor de top N gebruik je sort_by(.rating) | reverse | .[:N].
Uitvoer formatteren (patronen 21–25)
Patroon 21 — CSV-uitvoer
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25}]' \
| jq -r '.[] | [.name, .age] | @csv'
# Output: "Alice",30
# "Bob",25
@csv plaatst aanhalingstekens om strings en escapet aanhalingstekens erin. -r verwijdert de buitenste JSON-aanhalingstekens zodat de CSV direct doorgestuurd kan worden. Voor de volledige round-trip tussen CSV en JSON in pipelines, zie de CSV naar JSON-conversiegids.
Patroon 22 — TSV-uitvoer
echo '[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]' \
| jq -r '.[] | [.id, .name] | @tsv'
# Output: 1 Alice
# 2 Bob
Tab-gescheiden uitvoer werkt goed met cut, awk en column -t.
Patroon 23 — Ruwe string-uitvoer
echo '["alpha","beta"]' | jq -r '.[]'
# Output: alpha
# beta
Zonder -r zou elke regel aanhalingstekens hebben. Ruwe uitvoer is wat je doorgeeft aan xargs, while read of een andere shell-opdracht.
Patroon 24 — NDJSON / JSON Lines
echo '[{"a":1},{"a":2}]' | jq -c '.[]'
# Output: {"a":1}
# {"a":2}
Elke regel is een zelfstandige JSON-waarde — het formaat dat Kafka, Elasticsearch en de meeste gestructureerde loggers gebruiken. -c verwijdert ook alle interne witruimte.
Patroon 25 — String-interpolatie voor opgemaakte uitvoer
echo '[{"name":"server-1","cpu":0.73},{"name":"server-2","cpu":0.21}]' \
| jq -r '.[] | "\(.name): \(.cpu * 100)% CPU"'
# Output: server-1: 73% CPU
# server-2: 21% CPU
Ideaal voor samenvattingen en logregels waarbij ruwe JSON ruis zou zijn.
DevOps in de praktijk (patronen 26–30)
Patroon 26 — kubectl: namen van alle draaiende pods
kubectl get pods -o json \
| jq -r '.items[] | select(.status.phase=="Running") | .metadata.name'
Pipeline: itereer over pods, behoud alleen Running, geef de naam terug als ruwe string.
Patroon 27 — AWS EC2: instance-ID’s met publieke IP’s
aws ec2 describe-instances \
| jq -r '.Reservations[].Instances[] | [.InstanceId, .PublicIpAddress // "none"] | @tsv'
De //-alternatief-operator levert een terugvalwaarde als het veld null is — waardoor je geen letterlijke null in de uitvoerkolom krijgt.
Patroon 28 — GitHub API: gepagineerde resultaten samenvoegen
for p in 1 2 3; do
curl -s "https://api.github.com/orgs/myorg/repos?per_page=100&page=$p"
done | jq -s 'add | map(.name)'
-s slurpt alle responses in één array-van-arrays, add voegt ze samen, en map(.name) extraheert namen. Een veelgebruikt patroon voor elke gepagineerde API.
Patroon 29 — Gestructureerde logbestanden filteren
cat app.log | jq -c 'select(.level=="error")'
Dit gaat ervan uit dat het logbestand NDJSON is (één JSON-object per regel). Combineer met tail -f voor live monitoring:
tail -f app.log | jq -c 'select(.level=="error") | {ts: .timestamp, msg: .message}'
Patroon 30 — Docker: alle gebruikte image-namen
docker inspect $(docker ps -q) | jq -r '.[].Config.Image' | sort -u
Handig om snel te controleren welke image-versies op een host draaien.
Veelvoorkomende fouten en hoe je ze oplost
Elke jq-gebruiker loopt hier vroeg of laat tegenaan. De oplossing van tevoren kennen bespaart uren.
Cannot iterate over null (null)
Het veld dat je probeerde te itereren was null of ontbrak. Twee oplossingen:
# Optie A: optionele operator
echo '{}' | jq '.items[]?'
# Output: (niets, geen fout)
# Optie B: alternatieve operator met standaardwaarde
echo '{}' | jq '(.items // [])[]'
# Output: (niets, geen fout)
Gebruik ? als je stilletjes wil overslaan. Gebruik // [] als je een concrete lege array wil afdwingen zodat filters verderop nog steeds worden uitgevoerd.
Cannot index array with "key"
Je schreef .foo maar de huidige waarde is een array. Voeg [] toe om te itereren:
# Fout
echo '{"users":[{"name":"Alice"}]}' | jq '.users.name'
# Error: Cannot index array with "name"
# Goed
echo '{"users":[{"name":"Alice"}]}' | jq '.users[].name'
# Output: "Alice"
Problemen met aanhalingstekens in de shell
Gebruik enkele aanhalingstekens rondom het volledige jq-programma, dubbele aanhalingstekens binnenin voor string-literals:
# Werkt overal
jq '.users[] | select(.role == "admin")'
# Werkt niet — dubbele aanhalingstekens worden eerst door de shell geïnterpreteerd
jq ".users[] | select(.role == \"admin\")"
Randgevallen in Windows PowerShell
PowerShell behandelt enkele aanhalingstekens anders. Gebruik bij voorkeur dubbele aanhalingstekens rondom het programma en escape de binnenste aanhalingstekens, of gebruik een here-string:
jq "@'
.users[] | select(.role == \"admin\")
'@"
Sla bij alles wat niet triviaal is de filter op in een .jq-bestand en voer jq -f filter.jq uit.
Onjuist gebruik van ruwe uitvoer
-r heeft alleen effect op string-resultaten. Een object ermee geven levert gewone JSON op:
echo '{"a":1}' | jq -r '.'
# Output: {"a":1} ← ongewijzigd; -r had niets te verwijderen
Als je een specifiek veld zonder aanhalingstekens wil, selecteer het dan eerst: jq -r '.a'.
jq wijst JSON met commentaar of trailing comma’s af
echo '{"a": 1, /* note */ "b": 2,}' | jq .
# parse error: Invalid numeric literal
jq volgt strikte RFC 8259 JSON — geen commentaar, geen trailing comma’s, geen sleutels zonder aanhalingstekens. Als het bestand JSON5 of JSONC is (gebruikelijk voor configuratiebestanden), verwijder dan eerst de extensies. De JSON5- en JSONC-formatteerdersgids beschrijft welke parsers ze verwerken en hoe je ze omzet naar strikte JSON voordat je ze naar jq stuurt.
jq versus alternatieven: gron, fx, jj, yq
jq is niet de enige optie, en soms is een andere tool sneller:
| Tool | Sterk punt | Wanneer je het inzet |
|---|---|---|
| gron | Vlakt JSON af tot grep-bare paden | Onbekende schema’s verkennen — je weet niet waar de sleutel zit |
| fx | Interactieve TUI-verkenner met markering | Grote JSON handmatig doorbladeren |
| jj | Veel sneller dan jq, beperkte syntaxis | Loops die miljoenen records verwerken |
| yq | Dezelfde filtertaal maar voor YAML | Kubernetes-manifesten en CI-configuratie |
| Browser JSON Formatter | Syntaxismarkering, nauwkeurige foutmeldingen, geen installatie | Eén response debuggen tijdens het ontwikkelen |
Voor dagelijks shell-werk wint jq op samenstellbaarheid. Voor eenmalige verkenning is gron vaak sneller. Voor YAML gebruik je yq — probeer niet door yq-then-jq te pipen.
Aanbevolen aanpak voor dagelijks gebruik
Een paar gewoonten die jq vertrouwd laten aanvoelen:
-
Houd een
.jqrcbij in$HOME. Plaats hulpfuncties daarin, zodat ze beschikbaar zijn in elkejq-aanroep:def running: select(.status.phase == "Running"); def table(f): [f] | @tsv; -
Gebruik jqplay.org voor complexe filters. Plak je JSON links, itereer de filter rechts en zet de werkende versie in je script.
-
Bouw je eigen spiekbriefje uit
history.history | grep 'jq ' | sort -u > ~/jq-patterns.txtlegt elk patroon vast dat je daadwerkelijk hebt gebruikt. -
Combineer met de browser JSON Formatter voor onbekende schema’s. Verken de structuur visueel om het pad te vinden dat je nodig hebt, en schrijf dan de
jq-opdracht. -
Bekijk live waarden:
watch -n 5 "curl -s api.example.com/health | jq '.uptime'"ververst elke 5 seconden — een snel ops-dashboard zonder afhankelijkheden.
Veelgestelde vragen
Wat is jq en waarom gebruiken ontwikkelaars het?
jq is een JSON-verwerker voor de commandoregel. Het extraheert, filtert en transformeert JSON in shell-pipelines zonder Python- of Node-script — de snelste weg van API-responses, logbestanden of kubectl-uitvoer naar het veld dat je daadwerkelijk nodig hebt.
Is jq beschikbaar op Windows?
Ja. Installeer via winget install jqlang.jq, Chocolatey choco install jq of download de binary van jqlang.org. De regels voor aanhalingstekens in PowerShell verschillen van bash — sla filters bij twijfel op in een .jq-bestand en voer jq -f filter.jq uit.
Hoe verschilt jq van een browser-JSON-formatter?
Een browser-JSON-formatter is interactief — plak JSON, zie markering en fouten, kopieer het resultaat. jq is niet-interactief — beschrijf de transformatie eenmalig en voer die uit in een shell-pipeline. Gebruik de browser om één response te debuggen; gebruik jq om dezelfde bewerking op honderden te automatiseren.
Waarom zegt jq “Cannot iterate over null”?
Je probeerde te itereren (.[]) over een waarde die null is — meestal omdat het veld ontbrak in de invoer. Gebruik de optionele operator .items[]? of geef een standaardwaarde met .items // [] | .[].
Kan jq bestanden in-place wijzigen?
Niet rechtstreeks — jq schrijft naar stdout. Gebruik een tijdelijk bestand of sponge uit moreutils: jq '.version = "2.0"' config.json | sponge config.json. Maak altijd eerst een back-up van het origineel; een verkeerd getypte filter overschrijft het bestand.
Hoe gebruik ik jq met curl-responses?
Geef curl -s door aan jq. De -s-vlag snoert de voortgangsmeter van curl zodat alleen de JSON-body jq bereikt:
curl -s https://api.github.com/users/octocat | jq '.name, .blog'
Wat is het verschil tussen de | van jq en de shell-|?
De shell-pipe stuurt bytes tussen processen. De jq-pipe stuurt JSON-waarden tussen filters binnen één jq-aanroep. Een enkele jq-opdracht met veel interne pipes draait in één proces — goedkoper dan het ketenen van jq | jq | jq.
Kan jq JSON Lines (NDJSON) verwerken?
Ja, standaard. jq leest elke regel als een zelfstandige JSON-waarde wanneer ze worden gescheiden door witruimte. Gebruik -c om NDJSON te produceren en -s om NDJSON in één array te verzamelen.
Hoe druk ik JSON netjes af zonder te filteren?
Gebruik de identiteitsfilter: cat data.json | jq . of gewoon jq . < data.json. Het verwerkt, valideert en drukt netjes af met twee spaties inspringing — geen filter nodig.
Is er een jq-alternatief met een GUI?
Ja. fx biedt een interactieve TUI. Voor een zero-install GUI dekt de JSON Formatter die in je browser draait de meeste behoeften voor verkennen en valideren. Web-tools als jqplay.org bieden jq zelf met een live voorbeeld.
Wanneer gebruik ik jq in plaats van een Python-script te schrijven?
Kies jq wanneer de taak eenmalig is, in een shell-pipeline past en binnen filter-, transformeer- en extraheersemantieken blijft. Stap over op Python als je unit-tests, complexe toestand, externe bibliotheken of vertakkingslogica nodig hebt die een .jq-bestand onleesbaar maakt.
Hoe gebruik ik reguliere expressies in jq?
jq biedt regex via test("patroon"), match("patroon"), capture("patroon") en scan("patroon"), allemaal met PCRE-syntaxis. Geef vlaggen mee als tweede argument: test("abc"; "i") voor hoofdletterongevoelig. match geeft offsets en captures terug; scan geeft elke niet-overlappende overeenkomst.
Kernpunten
- Kernmodel eerst: filter in, nul of meer JSON-waarden uit, samenstellen met
|. De rest is syntaxis. - Leer per taak, niet per operator: de 30 patronen hierboven dekken ongeveer 95% van dagelijks
jq-gebruik. - Verwerk null expliciet:
?voor stil overslaan,// standaardvoor een concrete terugvalwaarde. De meeste “Cannot iterate over null”-fixes zijn één van deze twee. - Weet wanneer
jqhet verkeerde gereedschap is: losse responses horen in een browser-JSON-formatter; YAML hoort inyq; complexe logica hoort in echte code. - Combineer met je bestaande stack:
jqschittert incurl-,kubectl-,aws-,docker- en log-pipelines. Gebruik het als bindmiddel, niet als logicalaag.
Zie voor gerelateerde JSON-workflows de JSON5- en JSONC-formatteerdersgids voor syntaxisextensies van configuratiebestanden, en de CSV naar JSON-conversiegids voor gegevensformaatmigraties waarbij jq in de pipeline past. Als je JSON tijdstempels bevat, behandelt de Unix-timestamp-gids de valkuilen die je tegenkomt bij het transformeren van datumvelden.