cClaude.rocks ☕ Le blog

[Nouvelles technologies, sciences et coups de gueule…]

Menu

jq est un processeur JSON en ligne de commande, elle permet de transformer un document JSON en un autre. Certaines options permettent de convertir depuis et vers d’autres formats.


ඏ

Les bases de la commande jq

La syntaxe est la suivante :

jq [options…] filtre [fichier…]

mais vous l’utiliserez sans doute plus souvent sous la forme :

UN_FLUX | jq [options…] filtre

ou encore :

jq [options…] filtre <<<"${UNE_VARIABLE}"

Le filtre le plus simple est ., il indique que l’on prend tout le flux d’entrée permettant de mettre en forme le document ou de le valider, par exemple :

echo '{"A":"a","B":true,"C":42}' | jq .

ඏ

Documentation jq

Notez que le résumé produit en invoquant jq avec l’option -h ne fournit pas une liste complète des options.

Pour connaître toutes les options supportées il faut se référer au manuel : jq Manual en anglais qui est disponible pour chacune des versions de jq (actuellement la dernière version est : 1.6).

Deux options non documentées sont à noter :

  • --debug-dump-disasm
  • --debug-trace

Il est également possible d’avoir la documentation depuis le terminal à l’aide de :

man jq

ඏ

Aide-mémoire

Prenons l’exemple suivant :

{
  "id": 42,
  "group-id": 42,
  "name": "nom du group",
  "group": [
    { "name":"nom un", "admin": false, "total": 100},
    { "name":"nom deux", "admin": true, "total": 200},
    { "name":"nom trois", "admin": false, "total": 300}
    ]
}

que vous mettrez dans la variable TEST à l’aide de :

TEST=$( cat <<EOF | jq -c .
{
  "id": 42,
  "group-id": 42,
  "name": "nom du group",
  "group": [
    { "name":"nom un", "admin": false, "total": 100},
    { "name":"nom deux", "admin": true, "total": 200},
    { "name":"nom trois", "admin": false, "total": 300}
    ]
}
EOF
)

Pour voir le contenu du flux JSON :

jq . <<<"${TEST}"

Pour extraire les attributs de premier niveau id et name :

jq '{"id", "name"}' <<<"${TEST}"

Notez que si le nom de l’attribut contient un caractère spécial comme le signe moins, vous devez utiliser la notation complète :

jq '{"group-id": .["group-id"], "name": .name}' <<<"${TEST}"

Pour extraire les attributs name et total de chacune des entrées du tableau :

jq '.group[] | {name, total}' <<<"${TEST}"

Pour extraire les attributs name et total au format texte au lieu du format JSON :

jq -r '.group[] | {name, total} | join(" ")' <<<"${TEST}"

Filtrer les résultats en fonction de la valeur d’un attribut :

jq '.group[] | select(.name == "nom deux") | {total}' <<<"${TEST}" # Au format JSON
jq '.group[] | select(.name == "nom deux") | .total' <<<"${TEST}" # Au format texte (c’est un nombre, le paramètre -r n’est pas nécessaire)

Filtrer avec plusieurs conditions :

jq '.group[] | select( (.name | contains("nom")) and (.total > 150))' <<<"${TEST}"

Filtrer avec l’opérateur not (inversion de la condition) :

jq -c '.group[] | select(.name | test("x") | not)' <<<"${TEST}" # récupère toutes les entrées pour les noms ne contenant pas de x

Pour obtenir un tableau JSON :

jq '[ .group[] | select(.name | test("x") | not) ]' <<<"${TEST}"

ඏ

Construire un document JSON à partir d’un fichier texte simple

Le fichier /proc/meminfo contiens les informations liées à la mémoire de votre machine.

cat /proc/meminfo

donne quelque chose comme :

MemTotal:        8000520 kB
MemFree:         7354312 kB
MemAvailable:    7795420 kB
Buffers:           52624 kB
Cached:           467256 kB
SwapCached:            0 kB
…

Si on souhaite transformer cet extrait en JSON, on va chercher à réécrire le texte ci-dessus comme suit :

{
  "MemTotal": "8000520 kB",
  "MemFree": "7353556 kB",
  "MemAvailable": "7794852 kB",
  "Buffers": "52632 kB",
  "Cached": "467436 kB",
  "SwapCached": "0 kB"
}

Si on cherche à produire naïvement ce fichier, il va falloir en particulier gérer le caractère , de manière particulière car, il est présent à la fin de toutes les lignes sauf la dernière.

On va plutôt chercher à créer le plus rapidement des objets JSON et les manipuler pour obtenir le résultat attendu.

La première étape sera donc de transformer :

MemTotal:        8000520 kB

en :

{"MemTotal":"8000520 kB"}

ඏ

Pour ce genre de situation, la commande sed est parfaite.

  • Explications de la syntaxe utilisée pour sed

    sed

    sed est un éditeur de flux pour le filtrage et la transformation de texte. On utilise un éditeur de flux pour effectuer des transformations de texte basiques sur un flux d’entrée (un fichier ou l’entrée d’un tube) et essentiellement dans le cadre d’une édition scriptée.

    echo 'ABC:DEF' | sed -E 's/^(.*):(.*)$/{"\1":"\2"}/'
    

    On utilise l’option -E (qui peut s’écrire également -r ou --regexp-extended) permettant d’utiliser les expressions régulières étendues.

    Explication de la transformation s/^(.*):(.*)$/{"\1":"\2"}/:

    • s : Indique que l’on souhaite faire une substitution.
    • / : Le séparateur du motif et de la chaîne de remplacement qui sera utilisé.
    • ^(.*):(.*)$ : Le motif à rechercher
    • / : Le séparateur
    • {"\1":"\2"} : la chaîne de substitution.
    • / : Le dernier séparateur qui sans option indique que la substitution ne doit se faire qu’une seule fois par ligne.

    Explication du motif ^(.*):(.*)$ :

    • ^ : indique que la suite du motif doit se trouver immédiatement en début de ligne.
    • (.*) : défini un groupe avec les parenthèses et ce groupe est composé de n’importe quel caractère (.) un nombre quelconque de fois (*).
    • ‘:’ : recherche le caractère :
    • (.*) : défini un groupe second groupe (avec les mêmes règles)
    • $ : indique que la fin de la ligne.

    Pour résumé indique à sed de considérer ce qui est au début de la ligne et ce jusqu’au caractère : comme un groupe et ce qu’il y a après ce caractère jusqu’à la fin comme un autre.

    Explication de la substitution {"\1":"\2"} :

    • { : écrit le caractère{
    • " : écrit le caractère"
    • \1 : écrit le contenu du 1er groupe
    • " : écrit le caractère"
    • : : écrit le caractère:
    • " : écrit le caractère"
    • \2 : écrit le contenu du 2nd groupe
    • " : écrit le caractère"
    • } : écrit le caractère}

    Mais vous aurez noté qu’en réalité, on voudrait traiter la chaîne ABC: DEF et non pas uniquement ABC:DEF. Pour cela il faut utiliser le commutateur [[:blank:]] (qui correspond à l’espace, mais aussi au caractère de tabulation) suivit du caractère * pour indiquer un nombre quelconque de fois.

    Et cela donne:

    echo 'ABC:  DEF' | sed -E 's,^(.*):[[:blank:]]*(.*)$,{"\1":"\2"},'
    

    Notez que j’ai changé le séparateur , au lieu de / car je trouve cela plus lisible et qu’en fait sed se fiche du caractère, du moment que c’est le même que vous utiliser pour toute l’expression.

Du coup, nous avons :

cat /proc/meminfo | sed -E 's,^(.*):[[:blank:]]*(.*)$,{"\1":"\2"},'

qui produit le résultat :

{"MemTotal":"16233556 kB"}
{"MemFree":"637928 kB"}
{"MemAvailable":"2792636 kB"}
{"Buffers":"211828 kB"}
{"Cached":"5106280 kB"}
{"SwapCached":"5608 kB"}

ඏ

Cela correspond à une succession d’objets JSON qu’il faudra mettre dans un seul objet JSON.

Pour commencer utilisons l’option --slurp de jq:

cat /proc/meminfo | sed -E 's,^(.*):[[:blank:]]*(.*)$,{"\1":"\2"},' | jq --slurp -c '.'

Cela donnera un tableau avec l’ensemble des lignes construites.

[{"MemTotal":"16233556 kB"},{"MemFree":"1630228 kB"},{"MemAvailable":"3154656 kB"},{"Buffers":"190940 kB"},{"Cached":"4336756 kB"},{"SwapCached":"6320 kB"}]

Il ne reste plus qu’à combiner tous ces objets dans un seul et comme on a un tableau la commande add de jq est parfaitement adaptée :

cat /proc/meminfo | sed -E 's,^(.*):[[:blank:]]*(.*)$,{"\1":"\2"},' | jq --slurp 'add'

Et voilà :

{
  "MemTotal": "8000520 kB",
  "MemFree": "7353556 kB",
  "MemAvailable": "7794852 kB",
  "Buffers": "52632 kB",
  "Cached": "467436 kB",
  "SwapCached": "0 kB"
}

Si vous souhaitez composer à votre

cat /proc/meminfo | head -n 3 | sed -E 's,^(.*):[[:blank:]]*(.*)$,{"\1":"\2"},' | jq --slurp -S '{ "memory": add }'
{
  "memory": {
    "MemAvailable": "3230012 kB",
    "MemFree": "1216544 kB",
    "MemTotal": "16233556 kB"
  }
}

ඏ

Autre billets et documentations :

ᦿ


ℹ 2006 - 2022 | 🏠 Accueil du domaine | 🏡 Accueil du blog