Comment formater une chaîne JSON en tant que table en utilisant jq?

Vient de commencer avec Bash scripting et est tombé sur jq pour travailler avec JSON.

J'ai besoin de transformer une chaîne JSON comme ci-dessous en une table pour la sortie dans le terminal.

[{
    "name": "George",
    "id": 12,
    "email": "george@domain.com"
}, {
    "name": "Jack",
    "id": 18,
    "email": "jack@domain.com"
}, {
    "name": "Joe",
    "id": 19,
    "email": "joe@domain.com"
}]

Ce que je veux afficher dans le terminal:

ID        Name
=================
12        George
18        Jack
19        Joe

Remarquez comment je ne veux pas afficher la propriété email pour chaque ligne, donc la commande jq devrait impliquer un filtrage. Ce qui suit me donne une liste simple de noms et d'identifiants:

list=$(echo "$data" | jq -r '.[] | .name, .id')
printf "$list"

Le problème avec cela est, Je ne peux pas l'afficher comme table. Je sais que jq a quelques options de formatage, mais pas aussi bonnes que les options que j'ai en utilisant printf. Je pense que je veux obtenir ces valeurs dans un tableau que je peux ensuite parcourir moi-même pour faire le formatage...? Les choses que j'ai essayées me donnent des résultats variables, mais jamais ce que je veux vraiment.

Quelqu'un peut-il me diriger dans la bonne direction?

23
demandé sur Micha Wiedenmann 2016-08-25 10:24:59

3 réponses

, Pourquoi pas quelque chose comme :

echo '[{
    "name": "George",
    "id": 12,
    "email": "george@domain.com"
}, {
    "name": "Jack",
    "id": 18,
    "email": "jack@domain.com"
}, {
    "name": "Joe",
    "id": 19,
    "email": "joe@domain.com"
}]' | jq -r '.[] | "\(.id)\t\(.name)"'

Sortie

12  George
18  Jack
19  Joe

Edit 1: pour le formatage à grain fin, utilisez des outils tels que awk

 echo '[{
    "name": "George",
    "id": 12,
    "email": "george@domain.com"
}, {
    "name": "Jack",
    "id": 18,
    "email": "jack@domain.com"
}, {
    "name": "Joe",
    "id": 19,
    "email": "joe@domain.com"
}]' | jq -r '.[] | [.id, .name] | @csv' | awk -v FS="," 'BEGIN{print "ID\tName";print "============"}{printf "%s\t%s%s",$1,$2,ORS}'
ID  Name
============
12  "George"
18  "Jack"
19  "Joe"

Edit 2 : En réponse à

Il n'y a aucun moyen que je puisse obtenir une variable contenant un tableau directement de jq?

Pourquoi pas?

Un exemple peu impliqué (en fait modifié à partir du vôtre ) où l'email est changé en un tableau démontre ce

echo '[{
    "name": "George",
    "id": 20,
    "email": [ "george@domain1.com" , "george@domain2.com" ]
}, {
    "name": "Jack",
    "id": 18,
    "email": [ "jack@domain3.com" , "jack@domain5.com" ]
}, {
    "name": "Joe",
    "id": 19,
    "email": [ "joe@domain.com" ]
}]' | jq -r '.[] | .email'

Sortie

[
  "george@domain1.com",
  "george@domain2.com"
]
[
  "jack@domain3.com",
  "jack@domain5.com"
]
[
  "joe@domain.com"
]
21
répondu sjsam 2016-08-25 09:06:20

L'utilisation du filtre @tsv a beaucoup à recommander, principalement parce qu'il gère de nombreux "cas de bord" de manière standard:

.[] | [.id, .name] | @tsv

L'ajout des en-têtes peut se faire comme suit:

jq -r '["ID","NAME"], ["--","------"], (.[] | [.id, .name]) | @tsv'

Le résultat:

ID  NAME
--  ------
12  George
18  Jack
19  Joe
32
répondu peak 2016-08-25 11:50:23

Si les valeurs ne contiennent pas d'espaces, cela peut être utile:

read -r -a data <<<'name1 value1 name2 value2'

echo "name value"
echo "=========="

for ((i=0; i<${#data[@]}; i+=2)); do
  echo ${data[$i]} ${data[$((i+1))]}
done

Sortie

name value
==========
name1 value1
name2 value2
0
répondu Micha Wiedenmann 2016-08-25 11:54:37