On a tous connu ça : une API qui renvoie une tartine de JSON, un docker inspect qui vous crache une structure de données digne d'un labyrinthe, ou encore Home Assistant qui expose ses états dans un format… disons, généreux. Dans un homelab, où on aime bien tout bricoler et tout automatiser, manipuler ces flots de JSON depuis la ligne de commande, ça peut vite devenir un enfer. On se retrouve à faire des grep hasardeux ou à ouvrir un éditeur de texte juste pour trouver une petite valeur. Et là, on perd un temps fou.
C'est là que jq entre en scène. J'ai découvert cet outil il y a quelques années, et depuis, il fait partie de mes indispensables. C'est un peu le sed ou le awk des données JSON, mais en bien plus puissant et surtout, en bien plus adapté à la structure des objets. Fini de s'arracher les cheveux pour extraire une info ou reformater une sortie : jq, c'est le couteau suisse qu'il vous faut.
Installer `jq` : rapide et indolore
Avant de plonger dans le vif du sujet, il faut l'installer. Heureusement, c'est un jeu d'enfant sur la plupart des systèmes. jq est un binaire écrit en C, donc pas de dépendances lourdes à la PHP ou Node.js, ce qui est plutôt une bonne nouvelle. La version stable actuelle est la 1.8.2, sortie le 20 juin 2026.
- Debian/Ubuntu :
sudo apt-get install jq - Fedora :
sudo dnf install jq - Arch Linux :
sudo pacman -S jq - macOS (Homebrew) :
brew install jq - Windows (Winget) :
winget install jqlang.jq
Pour les autres, il y a toujours la possibilité de télécharger le binaire précompilé depuis jqlang.org et de le placer dans votre PATH. Et si vous êtes un adepte de Docker, vous pouvez l'intégrer facilement dans vos images avec un simple curl.
Les bases de `jq` : voir clair dans le fouillis
La première chose que jq fait pour vous, c'est rendre le JSON lisible. Vous savez, quand une API vous renvoie un bloc sans un seul saut de ligne ?
echo '{\"name\":\"Arnaud\",\"age\":30,\"skills\":[\"PHP\",\"Linux\"]}' | jq '.'
Et là, magie :
{ \"name\": \"Arnaud\",\n \"age\": 30,\n \"skills\": [\n \"PHP\",\n \"Linux\"\n ]\n}
Déjà, ça aide ! Le . après jq, c'est le filtre identité : il prend l'entrée et la renvoie telle quelle, mais joliment formatée par défaut.
Maintenant, si je veux juste mon nom :
echo '{\"name\":\"Arnaud\",\"age\":30}' | jq '.name'
Ça me sort :
\"Arnaud\"
Notez les guillemets. Si vous voulez la valeur brute, sans les guillemets JSON, l'option -r (pour --raw-output) est votre amie :
echo '{\"name\":\"Arnaud\"}' | jq -r '.name'
Output : Arnaud. C'est souvent ce qu'on veut pour utiliser la sortie dans un script.
Pour les champs imbriqués, c'est aussi simple :
echo '{\"user\":{\"firstName\":\"Arnaud\",\"lastName\":\"Kadur\"}}' | jq '.user.firstName'
Output : \"Arnaud\"
Et pour les tableaux, on utilise les crochets :
echo '{\"skills\":[\"PHP\",\"Linux\",\"Docker\"]}' | jq '.skills[0]'
Output : \"PHP\"
Filtrer, c'est la vie : trouver l'aiguille dans la botte de foin
Là où jq devient vraiment puissant, c'est pour filtrer des listes d'objets. Imaginez que vous ayez une liste de conteneurs Docker (obtenue via l'API ou docker ps -a --format '{{json .}}') et que vous vouliez juste ceux qui sont arrêtés.
echo '[{\"name\":\"nginx\",\"status\":\"running\"},{\"name\":\"mysql\",\"status\":\"exited\"}]' | jq '.[] | select(.status == \"exited\")'
Ici, .[] déconstruit le tableau en un flux d'objets, et select(.status == "exited") ne laisse passer que ceux dont le statut est "exited".
{ \"name\": \"mysql\",\n \"status\": \"exited\"\n}
Le pipe | est la colonne vertébrale de jq. Il permet de chaîner les opérations, l'output d'un filtre devenant l'input du suivant. C'est comme ça qu'on construit des requêtes complexes, petit à petit.
Transformer et remodeler : quand le JSON ne fait pas ce qu'on veut
Parfois, on ne veut pas juste extraire des données, on veut les réorganiser, les agréger. jq excelle là-dedans aussi.
Prenons un exemple où je veux simplifier la sortie d'une API GitHub (en imaginant un commits.json) pour n'afficher que le message du commit et l'auteur :
jq '.[] | {message: .commit.message, author: .commit.author.name}' commits.json
Si commits.json contient un tableau de commits, cette commande va transformer chaque objet commit en un nouvel objet plus simple, avec seulement les champs message et author. Pratique pour une vue rapide ou pour alimenter un autre script.
On peut aussi utiliser map() pour appliquer une transformation à chaque élément d'un tableau et obtenir un nouveau tableau :
echo '[{\"id\":1,\"value\":10},{\"id\":2,\"value\":20}]' | jq 'map(.value * 2)'
Output : [20, 40]
Des fonctions comme length (taille d'un tableau ou d'une chaîne) ou keys[] (pour lister les clés d'un objet) sont aussi très utiles pour explorer ou manipuler la structure.
`jq` dans vos scripts de homelab : l'automatisation à portée de main
C'est dans l'automatisation que jq brille vraiment dans un homelab. Imaginez un script qui surveille l'état d'un service Docker, ou qui interroge l'API de votre Home Assistant pour faire des actions conditionnelles.
docker inspect mon-super-conteneur | jq -r '.[0].State.Status'
Ça me renverra "running", "exited", etc., directement utilisable dans un if de script shell.
Un point crucial pour l'intégration dans les scripts, c'est de passer des variables à jq de manière sécurisée. N'injectez jamais directement une variable shell dans la chaîne de filtre jq, c'est une porte ouverte aux problèmes de citation et de sécurité.
Utilisez plutôt --arg pour les chaînes et --argjson pour les valeurs JSON :
#!/bin/bash\nSERVICE_NAME=\"nginx\"\ndocker inspect ${SERVICE_NAME} | jq -r --arg service \"$SERVICE_NAME\" '.[0].Config.Labels[\"com.docker.compose.project\"] | select(. == $service)'
Ici, --arg service "$SERVICE_NAME" rend la variable shell SERVICE_NAME disponible dans jq sous le nom $service. C'est propre et robuste.
Les petits trucs qui agacent (et comment les éviter)
Même si jq est génial, il a ses petites particularités. Sa syntaxe, bien que logique, peut sembler un peu "hermétique" au début. On passe souvent par la documentation officielle ou le playground en ligne pour les requêtes un peu complexes. C'est normal, ne vous découragez pas.
Un piège classique, c'est l'opérateur []. Quand il est appliqué à un tableau, il déconstruit le tableau en un flux d'éléments séparés. Si vous l'appliquez à un objet, il renvoie un flux de ses valeurs. Ce comportement peut être déroutant au début, surtout quand on s'attend à un tableau en sortie et qu'on se retrouve avec plusieurs lignes.
Autre point : les performances. Pour des fichiers JSON très volumineux ou des structures profondément imbriquées (genre des dizaines de gigaoctets), jq peut montrer ses limites en termes de vitesse ou de consommation mémoire. Pour la plupart des usages de homelab, c'est amplement suffisant, mais si vous traitez des logs de production géants, vous pourriez vouloir regarder des alternatives comme gojq ou jaq (implémentations en Go et Rust, souvent plus rapides), ou même un script Python dédié.
Conclusion : `jq`, indispensable.
Honnêtement, jq est devenu un réflexe pour moi. Dès que je dois interagir avec du JSON en ligne de commande, il est là. Que ce soit pour déboguer une API, extraire des métriques de mes conteneurs, ou simplement comprendre la structure d'un fichier de configuration, il me fait gagner un temps précieux.
Si vous ne l'avez pas encore adopté, je vous encourage vivement à lui donner sa chance. C'est un de ces outils qui, une fois maîtrisés, transforment votre manière d'interagir avec vos systèmes. Un vrai must-have pour tout développeur ou homelabber qui se respecte. Et puis, c'est quand même plus classe que de faire des grep à l'aveuglette, non ?