0Pricing
DevOps Bootcamp · Lezione

Filtrare e selezionare JSON con le pipeline jq

Esplori oggetti e array annidati usando selettori jq, pipe e il filtro select.

Filtrare e selezionare JSON con le pipeline jq è una lezione DevOps Bootcamp gratuita su CoddyKit. Questa è la lezione 1 di 4. Puoi leggere la lezione completa qui gratuitamente — poi esercitati direttamente nel browser con un editor di codice integrato e un tutor IA disponibile 24/7. Fa parte del percorso di apprendimento DevOps Bootcamp, e i tuoi progressi si sincronizzano tra il web e l'app CoddyKit. Il corso DevOps Bootcamp include 4 lezioni in totale.

Che cos'è jq e perché usarlo?

jq è uno strumento da riga di comando leggero e potente per analizzare, filtrare e trasformare dati JSON. È il sed del JSON: gli si invia JSON tramite pipe e si ottiene in risposta un output strutturato.

  • Preinstallato nella maggior parte delle distribuzioni Linux o disponibile tramite apt install jq / brew install jq
  • Funziona perfettamente nelle pipeline shell con curl, cat e altri strumenti
  • Supporta filtraggio, mapping, riduzione e conversione di formato

L'invocazione di base è: jq '<filter>' file.json oppure tramite pipe con cat file.json | jq '<filter>'. Il filtro . (punto) è l'identità: formatta in modo leggibile l'intero documento.

# Pretty-print a JSON file
jq '.' data.json

# Or pipe from curl
curl -s https://api.github.com/users/torvalds | jq '.'

Selezione dei campi di un oggetto con la notazione a punti

Per accedere a un campo in un oggetto JSON, utilizzi la notazione a punti: .fieldName. Può concatenare i selettori per navigare tra oggetti annidati.

  • .name — campo di primo livello
  • .address.city — campo annidato
  • ."field-with-dash" — i campi con caratteri speciali richiedono le virgolette

Se il campo non esiste, jq restituisce null invece di generare un errore. Questo rende sicuro l'utilizzo negli script senza controlli aggiuntivi sui valori nulli per i campi opzionali.

# Given: {"name":"Alice","address":{"city":"Berlin","zip":"10115"}}
echo '{"name":"Alice","address":{"city":"Berlin","zip":"10115"}}' | jq '.name'
# Output: "Alice"

echo '{"name":"Alice","address":{"city":"Berlin","zip":"10115"}}' | jq '.address.city'
# Output: "Berlin"

Accesso agli elementi di un array e iterazione

Si accede agli array JSON con la notazione tra parentesi quadre. jq utilizza indici a partire da zero.

  • .items[0] — primo elemento
  • .items[-1] — ultimo elemento
  • .items[1:3] — sezione (dall'indice 1 fino a prima del 3)
  • .items[] — espande l'array: produce ogni elemento come valore separato (questo è l'iteratore)

L'iteratore [] è fondamentale nelle pipeline jq: consente di applicare i filtri successivi separatamente a ogni elemento.

# Given an array of users
echo '[{"name":"Alice"},{"name":"Bob"},{"name":"Carol"}]' | jq '.[0]'
# Output: {"name":"Alice"}

# Iterate all elements and extract .name from each
echo '[{"name":"Alice"},{"name":"Bob"},{"name":"Carol"}]' | jq '.[].name'
# Output:
# "Alice"
# "Bob"
# "Carol"

Creazione di pipeline jq con l'operatore pipe

Proprio come la pipe della shell |, jq dispone di un proprio operatore pipe interno. Questo passa l'output di un filtro come input al filtro successivo.

  • jq '.users[] | .name' — itera sugli utenti, quindi estrae il nome di ciascuno
  • jq '.data | .items[] | .id' — raggiunge data, espande items ed estrae id

Le pipe all'interno di un'espressione jq consentono di creare trasformazioni complesse un passaggio alla volta. Ogni fase riceve ciò che ha prodotto la fase precedente, inclusi più valori generati da un iteratore.

Concetto fondamentale: quando un iteratore produce N valori, ogni filtro successivo viene eseguito N volte, una per ciascun valore.

# Nested pipeline: navigate -> iterate -> extract
echo '{"users":[{"name":"Alice","age":30},{"name":"Bob","age":25}]}' \
  | jq '.users[] | .name'
# Output:
# "Alice"
# "Bob"

# Chain more stages
echo '{"users":[{"name":"Alice","age":30},{"name":"Bob","age":25}]}' \
  | jq '.users[] | .age'
# Output:
# 30
# 25

Filtraggio con select()

Il filtro select(condition) lascia passare un valore solo se la condizione è vera; in caso contrario non produce alcun output. È l'equivalente jq di grep o di WHERE in SQL.

  • select(.age > 18) — conserva gli oggetti in cui age è maggiore di 18
  • select(.status == "active") — verifica l'uguaglianza
  • select(.name | startswith("A")) — test su una stringa annidato

Combini select con l'iteratore per filtrare gli array: .items[] | select(.active) produce solo gli elementi per cui .active è valutato come vero.

# Filter array elements by a condition
echo '[{"name":"Alice","age":30},{"name":"Bob","age":17},{"name":"Carol","age":25}]' \
  | jq '.[] | select(.age >= 18) | .name'
# Output:
# "Alice"
# "Carol"

# Filter by string equality
echo '[{"name":"Alice","role":"admin"},{"name":"Bob","role":"user"}]' \
  | jq '.[] | select(.role == "admin") | .name'
# Output: "Alice"

Ricostruzione di oggetti e array con {} e []

jq consente di rimodellare i dati costruendo nuovi oggetti con {} e nuovi array con [].

  • {name: .name, city: .address.city} — seleziona e rinomina i campi in un nuovo oggetto
  • [.items[] | .id] — raccoglie nuovamente in un array i valori iterati
  • Forma abbreviata: {name, age} equivale a {name: .name, age: .age}

Racchiudere una pipeline in [...] si chiama costruzione di un array ed è essenziale quando si desidera un array JSON come output anziché un flusso di valori.

# Reshape: keep only selected fields
echo '[{"id":1,"name":"Alice","password":"secret"},{"id":2,"name":"Bob","password":"secret"}]' \
  | jq '[.[] | {id, name}]'
# Output:
# [
#   {"id": 1, "name": "Alice"},
#   {"id": 2, "name": "Bob"}
# ]

# Collect filtered names into an array
echo '[{"name":"Alice","active":true},{"name":"Bob","active":false}]' \
  | jq '[.[] | select(.active) | .name]'
# Output: ["Alice"]

Utilizzo di array annidati e discesa ricorsiva

Il JSON del mondo reale è spesso profondamente annidato. jq offre due strumenti per la navigazione in profondità:

  • .a.b.c — percorso esplicito quando la struttura è nota
  • .. | .fieldName? — discesa ricorsiva: attraversa ogni nodo dell'albero e produce i valori nei nodi in cui esiste la chiave

L'operatore ? (try) sopprime gli errori quando un campo non esiste in un determinato nodo; è fondamentale quando si utilizza la discesa ricorsiva su alberi eterogenei.

Utilizzi la discesa ricorsiva con moderazione sui documenti di grandi dimensioni: visita ogni nodo e può essere lenta. Preferisca percorsi espliciti quando la struttura è prevedibile.

# Explicit deep path
echo '{"a":{"b":{"c":42}}}' | jq '.a.b.c'
# Output: 42

# Recursive descent: find all "id" values anywhere in the tree
echo '{"users":[{"id":1,"profile":{"id":99}},{"id":2}]}' \
  | jq '.. | .id?'
# Output:
# 1
# 99
# 2

Esempio pratico: analisi delle risposte API di curl

Uno dei casi d'uso più comuni di jq consiste nell'analizzare le risposte di API REST recuperate con curl. La combinazione di curl -s (silenzioso) con una pipeline jq consente di estrarre dati in modo pulito e adatto agli script.

  • Estrarre un singolo valore: curl -s URL | jq '.field'
  • Creare una tabella di riepilogo: iterare un array e ricostruire oggetti contenenti solo i campi necessari
  • Utilizzare -r (output non elaborato) per rimuovere le virgolette che racchiudono i valori stringa, una funzione essenziale quando li si assegna a variabili shell

Suggerimento: aggiunga sempre -r quando l'output di jq verrà utilizzato come variabile shell o inviato tramite pipe a un altro comando.

#!/usr/bin/env bash
# Fetch GitHub repo info and extract specific fields
REPO="torvalds/linux"
RESPONSE=$(curl -s "https://api.github.com/repos/${REPO}")

# Extract fields
STARS=$(echo "$RESPONSE" | jq -r '.stargazers_count')
LANG=$(echo  "$RESPONSE" | jq -r '.language')
DESC=$(echo  "$RESPONSE" | jq -r '.description')

echo "Stars : $STARS"
echo "Lang  : $LANG"
echo "Desc  : $DESC"

Utilizzo di map() e map_values()

jq offre due comode funzioni di ordine superiore per trasformare le collezioni:

  • map(f) — applica il filtro f a ogni elemento di un array e restituisce un nuovo array. Equivale a [.[] | f].
  • map_values(f) — applica f a ogni valore di un oggetto o array, preservando chiavi e indici.

Sono più leggibili rispetto a racchiudere manualmente le pipeline in [] e rappresentano lo stile jq idiomatico per le trasformazioni che devono rimanere array.

# map: extract a field from each element
echo '[{"name":"Alice","score":95},{"name":"Bob","score":80}]' \
  | jq 'map(.name)'
# Output: ["Alice", "Bob"]

# map with select: filter + transform in one step
echo '[{"name":"Alice","score":95},{"name":"Bob","score":60}]' \
  | jq 'map(select(.score >= 70) | .name)'
# Output: ["Alice"]

# map_values: multiply every value in an object by 2
echo '{"a":1,"b":2,"c":3}' | jq 'map_values(. * 2)'
# Output: {"a":2,"b":4,"c":6}

Gestione dei campi opzionali e dei valori predefiniti con //

I dati JSON provenienti da fonti esterne sono spesso incoerenti: alcuni campi possono mancare o avere valore null. jq offre l'operatore alternativo // (doppia barra) per fornire un valore predefinito.

  • .nickname // "anonymous" — utilizza .nickname se non è null o false, altrimenti utilizza "anonymous"
  • .count // 0 — valore predefinito numerico
  • Da combinare con select: select((.status // "inactive") == "active")

È molto più conciso dell'equivalente shell ${VAR:-default} e si integra facilmente in pipeline più lunghe.

# Provide defaults for missing/null fields
echo '[{"name":"Alice","role":"admin"},{"name":"Bob"}]' \
  | jq '[.[] | {name, role: (.role // "user")}]'
# Output:
# [
#   {"name": "Alice", "role": "admin"},
#   {"name": "Bob",   "role": "user"}
# ]

# Numeric default
echo '{"items":[1,2,3]}' | jq '.total // 0'
# Output: 0

Script pratico: parser di log JSON

La registrazione strutturata in JSON è uno standard nei sistemi moderni. Ecco uno script realistico che legge un file di log JSON delimitato da newline, filtra le voci di errore e formatta un riepilogo leggibile.

Modelli principali utilizzati:

  • -c (output compatto) — un oggetto JSON per riga, utile per l'invio tramite pipe ai cicli shell
  • --arg name value — inserisce una variabile shell come argomento stringa di jq
  • select per filtrare in base al livello del log
  • -r per ottenere output stringa non elaborato, adatto a echo
#!/usr/bin/env bash
# Parse newline-delimited JSON logs and report ERRORs
# Each log line: {"level":"ERROR","msg":"...","ts":"2024-01-15T10:23:00Z","svc":"auth"}

LOG_FILE="/var/log/app/app.log"
LEVEL="ERROR"

echo "=== $LEVEL entries in $LOG_FILE ==="

jq -r --arg lvl "$LEVEL" \
  'select(.level == $lvl) | "[\(.ts)] [\(.svc)] \(.msg)"' \
  "$LOG_FILE"

# Count errors per service
echo ""
echo "=== Error count by service ==="
jq -r --arg lvl "$LEVEL" \
  'select(.level == $lvl) | .svc' "$LOG_FILE" \
  | sort | uniq -c | sort -rn

Verifica delle conoscenze: comportamento di select() in jq

Verifichi la Sua comprensione del funzionamento di select() all'interno di una pipeline jq.

Consideri il seguente comando:

echo '[{"name":"Alice","age":30},{"name":"Bob","age":17},{"name":"Carol","age":22}]' | jq '[.[] | select(.age >= 18) | .name]'

Quale sarà l'output?

Riepilogo della lezione: pipeline jq per filtrare JSON

Ha visto gli strumenti fondamentali di jq per esplorare e filtrare JSON dalla riga di comando:

  • Notazione con il punto (.field, .a.b.c) seleziona i campi degli oggetti
  • Accesso agli array (.[0], .[]) indicizza gli array e ne scorre gli elementi
  • Operatore pipe (|) concatena i filtri; ogni fase elabora tutti i valori della fase precedente
  • select(cond) filtra i valori, lasciando passare solo quelli per cui la condizione è vera
  • Costruzione di oggetti e array ({}, [], map()) ristruttura i dati in nuove strutture
  • Operatore alternativo (//) fornisce valori predefiniti per i campi null o mancanti
  • Flag -r rimuove le virgolette per assegnare valori a variabili della shell; --arg inserisce in modo sicuro le variabili della shell
  • Discesa ricorsiva (.. | .field?) cerca in profondità negli alberi annidati quando il percorso non è noto

Con questi strumenti può trasformare qualsiasi risposta di un'API JSON, file di log o configurazione nei dati di cui hanno bisogno i Suoi script, senza mai uscire dal terminale.

Domande Frequenti

La lezione «Filtrare e selezionare JSON con le pipeline jq» è gratuita?

Sì — il testo completo di «Filtrare e selezionare JSON con le pipeline jq» è gratuito qui sul web. Per esercitarvi in modo interattivo (un editor di codice integrato e un tutor IA 24/7) e sbloccare il resto del corso DevOps Bootcamp, passa a CoddyKit PRO. Il corso DevOps Bootcamp include 4 lezioni in totale.

Cosa imparerò in «Filtrare e selezionare JSON con le pipeline jq»?

Esplori oggetti e array annidati usando selettori jq, pipe e il filtro select. Eserciti DevOps Bootcamp con codice pratico che esegui direttamente nel browser, e un tutor IA 24/7 risponde alle tue domande mentre lavori sulla lezione.

Ho bisogno di esperienza per iniziare DevOps Bootcamp?

Non è richiesta alcuna esperienza precedente. DevOps Bootcamp su CoddyKit è strutturato per principianti e studenti avanzati, quindi puoi iniziare da qui o dall'inizio e procedere al tuo ritmo. Questa è la lezione 1 di 4.

Quanto tempo richiede la lezione «Filtrare e selezionare JSON con le pipeline jq»?

La maggior parte delle lezioni CoddyKit richiede circa 5–10 minuti. Ogni lezione è breve e interattiva, quindi fai progressi costanti e riprendi esattamente da dove hai lasciato su web e app.

Posso scrivere ed eseguire codice in questa lezione DevOps Bootcamp?

Sì. Ogni lezione DevOps Bootcamp include un editor di codice integrato, quindi scrivi ed esegui codice reale direttamente nel tuo browser e ricevi feedback istantaneo dall'IA — nessuna configurazione locale necessaria.

Tutte le lezioni di questo corso

  1. Filtrare e selezionare JSON con le pipeline jq
  2. Trasformare e costruire oggetti JSON con jq
  3. Usare insieme curl e jq per consumare API REST
  4. Modificare file di configurazione YAML con yq
← Torna a DevOps Bootcamp