cClaude.rocks ☕ Le blog

[Nouvelles technologies du libre, sciences et coups de gueule…]

Menu

Retour sur la function map() de la commande jq et on se propose de construire la réciproque de la sortie de la commande column.



Dans l’article 🐚 JSON et la commande column on a vu que la commande column lorsqu’on utilise le format JSON donnait un résultat du type :

{
   "table": [
      {
         "col1": "value1-1",
         "col2": "value2-1",
         "col3": "value3-1"
      },{
         "col1": "value1-2",
         "col2": "value2-2 beaucoup plus longue que les autres",
         "col3": "value3-2"
      }
   ]
}

On simplifiera cette sortie à l’aide de :

jq '.table'

et dans la suite, on considéra, le code JSON suivant :

[
  {
    "col1": "value1-1",
    "col2": "value2-1",
    "col3": "value3-1"
  },
  {
    "col1": "value1-2",
    "col2": "value2-2 beaucoup plus longue que les autres",
    "col3": "value3-2"
  }
]

Que l’on peut construire à l’aide de :

echo '[{"col1":"value1-1","col2":"value2-1","col3":"value3-1"},{"col1":"value1-2","col2":"value2-2 beaucoup plus longue que les autres","col3":"value3-2"}]'


Reconstruire les colonnes

Séparation des lignes

On va d’abord extraire chaque ligne à l’aide .[] (on ajoute le drapeau --raw-output / -r afin de mieux comprendre le résultat affiché):

echo '[{"col1":"value1-1","col2":"value2-1","col3":"value3-1"},{"col1":"value1-2","col2":"value2-2 beaucoup plus longue que les autres","col3":"value3-2"}]' |
  jq -c '.[]'

On a alors un flux qui ressemble à ceci :

{"col1":"value1-1","col2":"value2-1","col3":"value3-1"}
{"col1":"value1-2","col2":"value2-2 beaucoup plus longue que les autres","col3":"value3-2"}

Séparation des colonnes d’une ligne

Ensuite sur chacune des lignes, pour ne récupérer la uniquement la valeur, on va d’abord séparer les clés et des valeurs de chaque colonne à l’aide de la méthode to_entries suivi de .[].value.

echo '{"col1":"value1-1","col2":"value2-1","col3":"value3-1"}' |
  jq -r 'to_entries'

La fonction to_entries produira pour chaque ligne quelque chose comme ça :

[
  {
    "key": "col1",
    "value": "value1-1"
  },
  {
    "key": "col2",
    "value": "value2-1"
  },
  {
    "key": "col3",
    "value": "value3-1"
  }
]

Pour ne garder que la valeur, on sépare les éléments du tableau et on ne prend que le champ value, mais comme pour la suite on a besoin d’un tableau on encadre le résultat avec [ et ] :

echo '[{"key":"col1","value":"value1-1"},{"key":"col2","value":"value2-1"},{"key":"col3","value":"value3-1"}]' |
  jq '[.[].value]'

Ici on remarque que l’on met dans un tableau ([]) le résultat de quelque chose qui provient des éléments d’un tableau (.[]). Ceci correspond typiquement au cas d’usage de la fonction map().


Avec la fonction map() on écrira :

echo '[{"key":"col1","value":"value1-1"},{"key":"col2","value":"value2-1"},{"key":"col3","value":"value3-1"}]' |
  jq 'map( .value )'

Sans surprise on la liste des valeurs :

[
  "value1-1",
  "value2-1",
  "value3-1"
]

Il ne reste plus qu’à demander à jq à nous mettre ce tableau en colonnes. Cela se fait à l’aide de la méthode @tsv (“Tabulation Separated Values”):

echo '["value1-1","value2-1","value3-1"]' |
  jq --raw-output @tsv

On a alors ceci :

value1-1    value2-1    value3-1

En marge :

  • Le drapeau `--raw-output` / `-r`
    • --raw-output / -r :

      Avec cette option, si le résultat du filtre est une chaîne de caractères, il sera écrit directement sur la sortie standard plutôt que d’être formaté comme une chaîne JSON avec des guillemets. Cela peut être utile pour faire dialoguer les filtres jq avec des systèmes non basés sur JSON*.

    • --raw-output0 :

      Comme -r mais jq affichera le caractère NUL au lieu d’un saut de ligne après chaque sortie. De même pour les autres caractères de formatage comme la tabulation.



Résumons

Après l’analyse de ce qu’il se passe ligne par ligne, on va faire le calcul complet pour le flux JSON initial :

echo '[{"col1":"value1-1","col2":"value2-1","col3":"value3-1"},{"col1":"value1-2","col2":"value2-2 beaucoup plus longue que les autres","col3":"value3-2"}]' |
  jq -r '.[] | to_entries | map( .value ) | @tsv'

Voici ce que ça donne :

value1-1    value2-1    value3-1
value1-2    value2-2 beaucoup plus longue que les autres    value3-2

On note que pour un affichage ce n’est pas parfait, puisqu’on a un décalage dans les colonnes.



Fignolons

On a vu dans le billet 🐚 JSON et la commande column la commande column que l’on peut utiliser ici dans son usage principal, comme suit :

echo '[{"col1":"value1-1","col2":"value2-1","col3":"value3-1"},{"col1":"value1-2","col2":"value2-2 beaucoup plus longue que les autres","col3":"value3-2"}]' |
  jq -r '.[] | to_entries | map( .value ) | @tsv' |
  column --table --separator $'\t'

Notez qu’il faut définir le séparateur comme étant le caractère de tabulation et cela s’écrit en bash : $'\t'.

On a un résultat nettement plus satisfaisant :

value1-1  value2-1                                      value3-1
value1-2  value2-2 beaucoup plus longue que les autres  value3-2


Liens

ᦿ


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