Skip to Content
CLIjq

🐤 jq

Manipuler du JSON depuis un terminal : filtrer des réponses API, inspecter des logs, transformer des payloads.

jq (JSON processor) est l’outil de référence pour le traitement JSON en ligne de commande. Syntaxe déclarative, composition de filtres, zéro dépendance.

Installation

# Debian / Ubuntu sudo apt install jq # macOS (Homebrew) brew install jq # Alpine apk add jq

Flags essentiels

FlagRôle
-rSortie brute (sans guillemets autour des chaînes)
-cSortie compacte (une ligne)
-s (slurp)Rassembler toute l’entrée en un tableau
-STrier les clés des objets
-MSortie en mode couleurs (pour less -R)
# Extraction simple — les chaînes sont entre guillemets echo '{"nom": "Arthur"}' | jq '.nom' # → "Arthur" # Sortie brute echo '{"nom": "Arthur"}' | jq -r '.nom' # → Arthur

Piège : sans -r, jq retourne les chaînes entre guillemets doubles. Pour passer le résultat à une autre commande (echo, ssh, curl), ajouter -r.

Accès aux champs

SyntaxeRésultat
.champValeur du champ champ
.champ | keysListe des clés de l’objet
.[0]Premier élément du tableau
.[]Dépiler chaque élément
.champ1.champ2Champ imbriqué
.champ["clé"]Clé avec caractères spéciaux
.[]?.champAccès sûr (saute null)
# Objet imbriqué echo '{"user": {"nom": "Alice", "âge": 30}}' | jq '.user.nom' # → "Alice" # Tableau d'objets — dépiler tous les noms echo '[{"nom": "A"}, {"nom": "B"}]' | jq '.[].nom' # → "A" # → "B" # Accès sûr : ne pas planter si le champ est manquant echo '{"nom": "A"}' | jq '.prénom // "inconnu"' # → "inconnu"

Filtres fondamentaux

select — filtrer les éléments

# Ne garder que les éléments où le champ satisfait la condition echo '[1, 5, 10, 15]' | jq '[.[] | select(. > 8)]' # → [10, 15] # Dans un flux d'objets echo '[{"role": "admin"}, {"role": "user"}]' | jq '.[] | select(.role == "admin")' # → {"role": "admin"}

map — transformer chaque élément

# Doubler chaque nombre echo '[1, 2, 3]' | jq 'map(. * 2)' # → [2, 4, 6] # Extraire un champ de chaque objet echo '[{"nom": "A", "id": 1}, {"nom": "B", "id": 2}]' | jq 'map(.nom)' # → ["A", "B"]

group_by — regrouper

echo '[ {"dept": "vendeur", "rev": 100}, {"dept": "dev", "rev": 200}, {"dept": "vendeur", "rev": 150} ]' | jq 'group_by(.dept)' # → [[{...vendeur, 100}, {...vendeur, 150}], [{...dev, 200}]]

group_by trie d’abord le tableau par la clé, puis groupe les éléments adjacents.

flatten — aplatir les tableaux imbriqués

echo '[[1, 2], [3, 4]]' | jq 'flatten' # → [1, 2, 3, 4] echo '[[1, [2, 3]], [4]]' | jq 'flatten(2)' # → [1, 2, 3, 4] (profondeur 2)

reduce — accumuler

# Somme des éléments echo '[1, 2, 3, 4]' | jq 'reduce .[] as $x (0; . + $x)' # → 10 # Construire un objet depuis un tableau echo '[{"k": "a", "v": 1}, {"k": "b", "v": 2}]' | \ jq 'reduce .[] as $item ({}; .[$item.k] = $item.v)' # → {"a": 1, "b": 2}

Fonctions pratiques

FonctionRôle
lengthLongueur d’une chaîne, taille d’un tableau, nombre de clés
any(cond)Vrai si au moins un élément satisfait la condition
all(cond)Vrai si tous les éléments satisfont la condition
index(val)Index de val dans le tableau, ou null
IN(val; arr...)Vrai si val est dans l’un des arguments
test(regex)Vrai si la chaîne correspond à l’expression régulière
contains(str)Vrai si la chaîne contient str
ascii_downcaseMinuscules (ASCII uniquement)
ascii_upcaseMajuscules (ASCII uniquement)
emptyNe produit aucune valeur (filtre tout)
# Longueur echo '[1, 2, 3]' | jq 'length' # → 3 # any / all echo '[true, false, true]' | jq 'any' # → true echo '[true, true]' | jq 'all' # → true # index echo '[10, 20, 30]' | jq 'index(20)' # → 1 # test — vérifier un motif echo '"bonjour@exemple.fr"' | jq 'test("@.*\\.fr$")' # → true # IN — appartenance echo '"b"' | jq 'IN("a"; "b"; "c")' # → true

Usages courants

Extraire un champ d’un fichier JSON

# Un seul objet jq '.data.id' fichier.json # Chaque élément d'un tableau jq '.items[].name' fichier.json

Manipuler un payload pour curl

# Construire un JSON pour POST jq -n --arg nom "Alice" --argjson âge 30 \ '{nom: $nom, âge: $âge}' # → {"nom":"Alice","âge":30}

Filtrer les logs JSON (Docker, Kubernetes)

# Entrées en erreur docker logs --since 1h container | jq -r 'select(.level == "error") | .message' # Compter les niveaux de log docker logs container | jq -s 'group_by(.level) | map({niveau: .[0].level, count: length})'

Modifier un champ dans un fichier (édition in-place)

# Attention : remplace le fichier original jq '.config.timeout = 30' config.json > tmp.json && mv tmp.json config.json

Pipelines Kubernetes et Docker

BesoinCommande
Noms des podskubectl get pods -o json | jq -r '.items[].metadata.name'
IPs des podskubectl get pods -o json | jq -r '.items[].status.podIP'
Containers en erreurkubectl get pods -o json | jq -r '.items[] | select(.status.containerStatuses[]?.state.waiting != null) | .metadata.name'
Logs formatés JSONdocker logs --format json container | jq -r '"\(.time) [\(.level)] \(.message)"'

Pitfalls

  • Clés avec espaces ou tirets : utiliser la notation . uniquement pour les identifiants valides. Pour .my-key ou .my key, écrire ."my-key" ou ["my key"].
  • Sortie blanche dans un pipeline : oublier -r quand on passe jq à echo, ssh, ou xargs.
  • Slurp (-s) sur un gros fichier : tout charge en mémoire. Préférer le pipe pour les fichiers volumineux.
  • Indentation dans jq -n : utiliser --indent 0 pour éviter le reformatage du JSON produit.
  • Comparaison de chaînes : == fonctionne sur les strings, mais test est nécessaire pour les regex.
  • Fusion d’objets : {a, b} + {c} fusionne, mais + sur les tableaux concatène. * pour fusionner récursivement.