jq Cheat Sheet: 30 pattern JSON da riga di comando reali
Lanci kubectl get pods -o json in pipe verso less e il terminale si blocca davanti a un muro di JSON da due megabyte. Tutto ciò che vuoi è il nome di ogni pod nella fase Running. jq lo fa con tre caratteri di sintassi del filtro — una volta che conosci il vocabolario.
Questa non è una guida di riferimento sulla sintassi. Sono 30 pattern che digiterai davvero, raggruppati per attività che stai cercando di realizzare: accesso, filtraggio, trasformazione, aggregazione, formattazione e collegamento con strumenti reali come kubectl, aws e docker.
Quando usare jq vs un formattatore nel browser vs codice
jq non è sempre la risposta giusta. Le tre scelte oneste sono queste:
| Situazione | Strumento migliore | Perché |
|---|---|---|
| Una risposta API, serve evidenziazione sintassi e numeri di riga errore | Formattatore JSON nel browser | Diff visivo, zero setup, privato nel browser |
| Pipeline shell, elaborazione log, script CI, server remoto | jq | Componibile, scriptabile, nessuna dipendenza GUI |
| Logica di business, unit test, branching complesso | Codice in linguaggio (JS / Python) | Debugger reale, tipi, librerie |
Scegli jq quando il task vive dentro una pipeline shell — tutto il resto è probabilmente più facile altrove.
Installazione e la tua prima pipeline
jq è distribuito come singolo binario su ogni piattaforma principale:
# macOS
brew install jq
# Debian / Ubuntu
sudo apt install jq
# Windows (winget)
winget install jqlang.jq
Una prima pipeline, con il filtro identità:
curl -s https://api.github.com/users/octocat | jq .
Il filtro . prende il suo input ed emette inalterato, formattato in modo leggibile. Solo questo sostituisce la maggior parte dei momenti “fammi aprire questo JSON in un editor”.
Cinque flag coprono il 90% dell’uso reale:
| Flag | Scopo |
|---|---|
-r | Output raw — rimuove le virgolette circostanti dai risultati stringa |
-c | Compatto — un valore JSON per riga (NDJSON) |
-s | Slurp — legge tutti gli input in un singolo array |
-R | Input raw — legge le righe come stringhe invece che JSON |
-n | Input null — non legge stdin, usa null come input |
Il modello mentale di base: filtri e pipe
Un filtro prende un valore JSON come input e produce zero o più valori JSON come output. I filtri si compongono con un pipe |, che invia ogni output del filtro a sinistra come input al filtro a destra. Questo è lo stesso modello mentale dei pipe shell, solo con valori JSON che fluiscono invece che byte.
# . — identità
echo '{"name":"Alice"}' | jq '.'
# .key — accesso al campo
echo '{"name":"Alice"}' | jq '.name'
# .key.sub — percorso profondo
echo '{"user":{"email":"a@x.com"}}' | jq '.user.email'
# .[] — itera elementi array (produce output multipli)
echo '[{"id":1},{"id":2}]' | jq '.[] | .id'
# Composizione pipe: ogni output di .items[] alimenta .name
echo '{"items":[{"name":"a"},{"name":"b"}]}' | jq '.items[] | .name'
Questa è tutta la grammatica. I 30 pattern qui sotto sono combinazioni di queste primitive.
30 pattern che userai davvero
Ogni pattern mostra il JSON di input, il comando e l’output. Copia uno qualsiasi di essi nel tuo terminale.
Accesso ed estrazione (pattern 1–5)
Pattern 1 — Accesso sicuro con ?
Accedi a un campo che potrebbe non esistere senza crashare:
echo '{"name":"Alice"}' | jq '.address?.city?'
# Output: null
Il ? sopprime gli errori sulle chiavi mancanti. Senza, .address.city lancerebbe un errore di tipo se .address è assente.
Pattern 2 — Accesso a percorso profondo
echo '{"user":{"profile":{"email":"a@x.com"}}}' | jq '.user.profile.email'
# Output: "a@x.com"
Pattern 3 — Slicing di array
echo '[10,20,30,40,50]' | jq '.[1:3]'
# Output: [20, 30]
echo '[10,20,30,40,50]' | jq '.[-1]'
# Output: 50
Gli indici negativi contano dalla fine. Le slice usano intervalli semi-aperti, come Python.
Pattern 4 — Discesa ricorsiva per trovare ogni chiave corrispondente
echo '{"a":{"name":"x"},"b":[{"name":"y"},{"id":1}]}' | jq '.. | .name? | select(. != null)'
# Output: "x"
# "y"
.. percorre ogni valore nell’albero. Combinato con .name? e select, estrae ogni campo name indipendentemente dalla profondità — preziosissimo per esplorare schemi JSON sconosciuti.
Pattern 5 — Elenca tutte le chiavi di un oggetto
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 ordina alfabeticamente; keys_unsorted preserva l’ordine di inserimento.
Filtraggio (pattern 6–10)
Pattern 6 — Filtra un array per condizione
echo '[{"age":20},{"age":30},{"age":40}]' | jq 'map(select(.age > 25))'
# Output: [{"age":30},{"age":40}]
map(f) applica f a ciascun elemento; select(cond) mantiene solo gli elementi dove la condizione è vera.
Pattern 7 — Corrispondenza prefisso stringa
echo '[{"name":"api-gateway"},{"name":"web-ui"},{"name":"api-auth"}]' \
| jq '.[] | select(.name | startswith("api"))'
# Output: {"name":"api-gateway"}
# {"name":"api-auth"}
Anche utili: endswith("..."), contains("..."), test("^regex$").
Pattern 8 — Condizioni combinate
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 funzionano come ti aspetti.
Pattern 9 — Elimina campi sensibili
echo '{"user":"alice","password":"s3cret","token":"abc"}' | jq 'del(.password, .token)'
# Output: {"user":"alice"}
del() accetta percorsi multipli ed è sicuro se uno qualsiasi è mancante.
Pattern 10 — Deduplica per campo
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 deduplica valori interi; unique_by(f) deduplica per il risultato di un filtro.
Trasformazione (pattern 11–15)
Pattern 11 — Rinomina campi
echo '[{"first_name":"Alice","age":30}]' | jq 'map({name: .first_name, age})'
# Output: [{"name":"Alice","age":30}]
La forma abbreviata {age} è equivalente a {age: .age}.
Pattern 12 — Aggiungi un campo calcolato con interpolazione di stringa
echo '[{"first":"Alice","last":"Chen"}]' \
| jq 'map(. + {fullName: "\(.first) \(.last)"})'
# Output: [{"first":"Alice","last":"Chen","fullName":"Alice Chen"}]
\(expr) valuta expr e ne interpola il valore nella stringa.
Pattern 13 — Appiattisci array annidati
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 accetta un argomento di profondità opzionale: flatten(1) rimuove un solo livello.
Pattern 14 — Da oggetto ad array e ritorno
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}
Questa coppia abilita trasformazioni che richiedono di iterare sulle chiavi dell’oggetto — qualcosa che la sintassi a percorso col punto non può fare direttamente.
Pattern 15 — Deep-merge di due oggetti
echo '{"a":{"x":1},"b":2}' | jq '. * {a:{y:9}, c:3}'
# Output: {"a":{"x":1,"y":9},"b":2,"c":3}
L’operatore * esegue il deep-merge. Per il merge superficiale, usa + (vince il lato destro).
Aggregazione (pattern 16–20)
Pattern 16 — Lunghezza di array, oggetti e stringhe
echo '[1,2,3,4]' | jq 'length' # 4
echo '{"a":1,"b":2}' | jq 'length' # 2
echo '"hello"' | jq 'length' # 5
Pattern 17 — Somma un campo
echo '[{"price":10},{"price":25},{"price":5}]' | jq '[.[].price] | add'
# Output: 40
add somma numeri, concatena stringhe o unisce array — a seconda del tipo di input.
Pattern 18 — Raggruppa per campo
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}]]
Ogni gruppo diventa un array interno. Combina con map per aggregare per gruppo.
Pattern 19 — Ordina in ordine decrescente
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"}]
Le stringhe di data ISO 8601 si ordinano correttamente come stringhe. Per altri formati, fai prima il parsing — la guida ai timestamp Unix copre in profondità secondi epoch, millisecondi e conversione di fuso orario.
Pattern 20 — Max o min per campo
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, max_by restituiscono un singolo elemento. Per i top N, usa sort_by(.rating) | reverse | .[:N].
Formattare l’output (pattern 21–25)
Pattern 21 — Output CSV
echo '[{"name":"Alice","age":30},{"name":"Bob","age":25}]' \
| jq -r '.[] | [.name, .age] | @csv'
# Output: "Alice",30
# "Bob",25
@csv mette tra virgolette le stringhe e fa l’escape delle virgolette al loro interno. -r rimuove le virgolette esterne della stringa JSON così il CSV è direttamente convogliabile in pipe. Per il giro completo tra CSV e JSON nelle pipeline, vedi la guida alla conversione CSV verso JSON.
Pattern 22 — Output TSV
echo '[{"id":1,"name":"Alice"},{"id":2,"name":"Bob"}]' \
| jq -r '.[] | [.id, .name] | @tsv'
# Output: 1 Alice
# 2 Bob
L’output separato da tab si sposa bene con cut, awk e column -t.
Pattern 23 — Output stringa raw
echo '["alpha","beta"]' | jq -r '.[]'
# Output: alpha
# beta
Senza -r, ogni riga avrebbe le virgolette circostanti. L’output raw è ciò che dai in pasto a xargs, while read o un altro comando shell.
Pattern 24 — NDJSON / JSON Lines
echo '[{"a":1},{"a":2}]' | jq -c '.[]'
# Output: {"a":1}
# {"a":2}
Ogni riga è un valore JSON autonomo — il formato usato da Kafka, Elasticsearch e dalla maggior parte dei logger strutturati. -c rimuove anche tutti gli spazi bianchi interni.
Pattern 25 — Interpolazione di stringa per output formattato
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
Ottimo per riassunti e righe di log dove il JSON raw sarebbe rumore.
DevOps sul campo (pattern 26–30)
Pattern 26 — kubectl: nomi di ogni pod in esecuzione
kubectl get pods -o json \
| jq -r '.items[] | select(.status.phase=="Running") | .metadata.name'
Pipeline: itera i pod, mantieni solo Running, emetti il nome come stringa raw.
Pattern 27 — AWS EC2: ID istanza con IP pubblici
aws ec2 describe-instances \
| jq -r '.Reservations[].Instances[] | [.InstanceId, .PublicIpAddress // "none"] | @tsv'
L’operatore alternativo // fornisce un fallback quando il campo è null — evitando un letterale null nella colonna di output.
Pattern 28 — API GitHub: unisci risultati paginati
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 slurp tutte le risposte in un array di array, add le concatena, poi map(.name) estrae i nomi. Un pattern comune per qualsiasi API paginata.
Pattern 29 — Filtra file di log strutturati
cat app.log | jq -c 'select(.level=="error")'
Si assume che il file di log sia NDJSON (un oggetto JSON per riga). Abbinalo a tail -f per monitoraggio live:
tail -f app.log | jq -c 'select(.level=="error") | {ts: .timestamp, msg: .message}'
Pattern 30 — Docker: tutti i nomi delle immagini in uso
docker inspect $(docker ps -q) | jq -r '.[].Config.Image' | sort -u
Buono per verificare velocemente quali versioni di immagini stanno girando su un host.
Errori comuni e come risolverli
Ogni utente di jq incappa in questi. Conoscere la soluzione in anticipo fa risparmiare ore.
Cannot iterate over null (null)
Il campo di input che hai provato a iterare era null o mancante. Due soluzioni:
# Opzione A: operatore opzionale
echo '{}' | jq '.items[]?'
# Output: (niente, nessun errore)
# Opzione B: operatore alternativo con default
echo '{}' | jq '(.items // [])[]'
# Output: (niente, nessun errore)
Usa ? quando vuoi saltare in silenzio. Usa // [] quando vuoi forzare un array vuoto concreto in modo che i filtri a valle continuino a girare.
Cannot index array with "key"
Hai scritto .foo ma il valore corrente è un array. Aggiungi [] per iterare:
# Sbagliato
echo '{"users":[{"name":"Alice"}]}' | jq '.users.name'
# Errore: Cannot index array with "name"
# Giusto
echo '{"users":[{"name":"Alice"}]}' | jq '.users[].name'
# Output: "Alice"
Problemi di quoting nella shell
Usa virgolette singole attorno all’intero programma jq, virgolette doppie all’interno per i letterali stringa:
# Funziona ovunque
jq '.users[] | select(.role == "admin")'
# Si rompe — virgolette doppie interpretate prima dalla shell
jq ".users[] | select(.role == \"admin\")"
Casi limite con Windows PowerShell
PowerShell non tratta le virgolette singole allo stesso modo. Preferisci virgolette doppie attorno al programma e fai l’escape delle virgolette interne, o usa una here-string:
jq "@'
.users[] | select(.role == \"admin\")
'@"
Per qualsiasi cosa non banale, salva il filtro in un file .jq ed esegui jq -f filter.jq.
Uso scorretto dell’output raw
-r influenza solo i risultati stringa. Dargli un oggetto produce un normale oggetto JSON:
echo '{"a":1}' | jq -r '.'
# Output: {"a":1} ← invariato; -r non aveva niente da rimuovere
Se vuoi un campo specifico senza virgolette, selezionalo prima: jq -r '.a'.
jq rifiuta JSON con commenti o virgole finali
echo '{"a": 1, /* note */ "b": 2,}' | jq .
# parse error: Invalid numeric literal
jq segue lo stretto JSON RFC 8259 — niente commenti, niente virgole finali, nessuna chiave senza virgolette. Se il file è JSON5 o JSONC (comune per i file di configurazione), rimuovi prima le estensioni. La guida alla formattazione JSON5 e JSONC copre quali parser li gestiscono e come convertirli a JSON stretto prima di passarli in pipe a jq.
jq vs alternative: gron, fx, jj, yq
jq non è l’unica opzione, e a volte uno strumento diverso è più veloce:
| Strumento | Punto di forza | Quando ricorrervi |
|---|---|---|
| gron | Appiattisce JSON in percorsi grep-abili | Esplorare schemi sconosciuti — non sai dov’è la chiave |
| fx | Esploratore TUI interattivo con evidenziazione | Sfogliare a mano JSON di grandi dimensioni |
| jj | Molto più veloce di jq, sintassi limitata | Loop caldi che processano milioni di record |
| yq | Stesso linguaggio di filtri ma per YAML | Manifest Kubernetes e config CI |
| Formattatore JSON nel browser | Evidenziazione sintassi, messaggi di errore precisi, zero installazione | Debug di una singola risposta durante lo sviluppo |
Per il lavoro shell quotidiano, jq vince per componibilità. Per esplorazioni una tantum, gron è spesso più veloce. Per YAML, usa yq — non provare a fare pipe attraverso yq-poi-jq.
Pro tip per l’uso quotidiano
Alcune abitudini che rendono jq familiare:
-
Tieni un
.jqrcin$HOME. Inserisci lì le funzioni helper, e saranno disponibili in ogni invocazione dijq:def running: select(.status.phase == "Running"); def table(f): [f] | @tsv; -
Usa jqplay.org per filtri complessi. Incolla il tuo JSON a sinistra, itera il filtro a destra, spedisci la versione funzionante nel tuo script.
-
Costruisci il tuo cheat sheet da
history.history | grep 'jq ' | sort -u > ~/jq-patterns.txtcattura ogni pattern che hai effettivamente usato. -
Combina con il Formattatore JSON nel browser per schemi sconosciuti. Esplora prima la struttura visivamente per trovare il percorso che ti serve, poi scrivi il comando
jq. -
Osserva valori in tempo reale:
watch -n 5 "curl -s api.example.com/health | jq '.uptime'"aggiorna ogni 5 secondi — una rapida dashboard ops senza dipendenze.
FAQ
Cos’è jq e perché gli sviluppatori lo usano?
jq è un processore JSON da riga di comando. Estrae, filtra e trasforma JSON dentro pipeline shell senza uno script Python o Node — il percorso più veloce dalle risposte API, file di log o output di kubectl al campo che vuoi davvero.
jq è disponibile su Windows?
Sì. Installa via winget install jqlang.jq, Chocolatey choco install jq, o scarica il binario da jqlang.org. Le regole di quoting di PowerShell differiscono da bash — quando in dubbio, salva i filtri in un file .jq ed esegui jq -f filter.jq.
In cosa differisce jq da un formattatore JSON nel browser?
Un Formattatore JSON nel browser è interattivo — incolli JSON, vedi evidenziazione ed errori, copi il risultato. jq non è interattivo — descrivi la trasformazione una volta, la esegui attraverso una pipeline shell. Usa il browser per fare debug di una risposta; usa jq per automatizzare la stessa operazione su centinaia.
Perché jq dice “Cannot iterate over null”?
Hai provato a iterare (.[]) su un valore che è null — di solito perché il campo era mancante dall’input. Risolvi con l’operatore opzionale .items[]? o fornisci un default con .items // [] | .[].
jq può modificare i file in place?
Non direttamente — jq scrive su stdout. Usa un file temporaneo o sponge da moreutils: jq '.version = "2.0"' config.json | sponge config.json. Fai sempre prima un backup dell’originale; un filtro con un refuso sovrascriverà il file.
Come uso jq con risposte curl?
Passa curl -s in pipe a jq. Il flag -s silenzia il misuratore di progresso di curl così solo il corpo JSON raggiunge jq:
curl -s https://api.github.com/users/octocat | jq '.name, .blog'
Qual è la differenza tra il | di jq e il | della shell?
Il pipe shell invia byte tra processi. Il pipe di jq invia valori JSON tra filtri dentro un’unica invocazione di jq. Un singolo comando jq con molti pipe interni gira in un processo solo — più economico che concatenare jq | jq | jq.
jq può gestire JSON Lines (NDJSON)?
Sì, nativamente. jq legge ogni riga come un valore JSON indipendente quando sono separate da spazi bianchi. Usa -c per emettere NDJSON e -s per raccogliere NDJSON in un singolo array.
Come formatto JSON in modo leggibile senza filtrare?
Usa il filtro identità: cat data.json | jq . o semplicemente jq . < data.json. Fa il parsing, valida e formatta in modo leggibile con rientro a due spazi — nessun filtro richiesto.
Esiste un’alternativa a jq con una GUI?
Sì. fx fornisce una TUI interattiva. Per una GUI senza installazione, il Formattatore JSON basato su browser copre la maggior parte delle esigenze esplora-e-valida. Strumenti web come jqplay.org offrono jq stesso con anteprima live.
Quando dovrei usare jq invece di scrivere uno script Python?
Ricorri a jq quando il task è una tantum, sta in una pipeline shell e rimane dentro la semantica di filtro, trasformazione ed estrazione. Passa a Python quando ti servono unit test, stato complesso, librerie di terze parti o logica di branching oltre quanto un file .jq mantenga leggibile.
Come uso le espressioni regolari in jq?
jq espone regex via test("pattern"), match("pattern"), capture("pattern") e scan("pattern"), tutte usando sintassi PCRE. Passa flag come secondo argomento: test("abc"; "i") per case-insensitive. match restituisce offset e cattura; scan emette ogni match non sovrapposto.
Punti chiave
- Prima il modello mentale: filtro in entrata, zero o più valori JSON in uscita, componi con
|. Tutto il resto è sintassi. - Impara per task, non per operatore: i 30 pattern qui sopra coprono circa il 95% dell’uso quotidiano di
jq. - Gestisci null esplicitamente:
?per saltare in silenzio,// defaultper fallback concreto. La maggior parte delle correzioniCannot iterate over nullè una di queste due. - Sappi quando
jqè lo strumento sbagliato: le singole risposte appartengono a un Formattatore JSON nel browser; YAML appartiene ayq; la logica complessa appartiene al codice vero. - Abbinalo al tuo stack esistente:
jqbrilla dentrocurl,kubectl,aws,dockere pipeline di log. Usalo come collante, non come livello logico.
Per workflow JSON correlati, vedi la guida alla formattazione JSON5 e JSONC per le estensioni di sintassi dei file di configurazione, e la guida alla conversione CSV verso JSON per migrazioni di formato dati dove jq si inserisce nella pipeline. Quando il tuo JSON contiene timestamp, la guida ai timestamp Unix copre le insidie che incontrerai trasformando i campi data.