analyser un champ d'un tableau JSON dans un tableau bash

13

J'ai une sortie JSON qui contient une liste d'objets stockés dans une variable. (Je ne formule peut-être pas ce droit)

[
  {
    "item1": "value1",
    "item2": "value2",
    "sub items": [
      {
        "subitem": "subvalue"
      }
    ]
  },
  {
    "item1": "value1_2",
    "item2": "value2_2",
    "sub items_2": [
      {
        "subitem_2": "subvalue_2"
      }
    ]
  }
]

J'ai besoin de toutes les valeurs de item2 dans un tableau pour qu'un script bash soit exécuté sur ubuntu 14.04.1.

J'ai trouvé un tas de façons d'obtenir le résultat complet dans un tableau, mais pas seulement les éléments dont j'ai besoin

JpaytonWPD
la source

Réponses:

17

Utilisation de :

$ cat json
[
  {
    "item1": "value1",
    "item2": "value2",
    "sub items": [
      {
        "subitem": "subvalue"
      }
    ]
  },
  {
    "item1": "value1_2",
    "item2": "value2_2",
    "sub items_2": [
      {
        "subitem_2": "subvalue_2"
      }
    ]
  }
]

CODE:

arr=( $(jq -r '.[].item2' json) )
printf '%s\n' "${arr[@]}"

PRODUCTION:

value2
value2_2
Gilles Quenot
la source
Est-il possible de le faire à partir d'une variable au lieu d'un fichier? J'essaie d'éviter un accès excessif au système de fichiers si je n'en ai pas besoin. Une fois que je tire ce tableau, j'ai terminé avec la sortie json.
JpaytonWPD
1
As-tu essayé quelque chose?
Gilles Quenot
2
jq . <<< "$json"c'est lié à shell (bash), non spécifique àjq
Gilles Quenot
1
Parenthèses manquantes:arr=( $(...) )
Gilles Quenot
4
Excellente jqcommande, mais veuillez ne pas analyser la sortie de la commande dans un tableau avec arr=( $(...) )(même si cela fonctionne avec l'exemple d'entrée): cela ne fonctionne pas comme prévu avec les espaces blancs intégrés ou de début / fin et peut entraîner un globage accidentel.
mklement0
5

Ce qui suit est en fait un buggy:

# BAD: Output line of * is replaced with list of local files; can't deal with whitespace
arr=( $( curl -k "$url" | jq -r '.[].item2' ) )

Utilisez plutôt:

# GOOD (with bash 4.x+), but can't detect failure
readarray -t arr < <(curl -k "$url" | jq -r '.[].item2' )

... ou mieux encore ...

# GOOD (with bash 3.x+), *and* has nonzero status if curl or jq fails
IFS=$'\n' read -r -d '' -a arr \
  < <(set -o pipefail; curl --fail -k "$url" | jq -r '.[].item2' && printf '\0')
Charles Duffy
la source
2

Grâce à sputnick, je suis arrivé à ceci:

arr=( $(curl -k https://localhost/api | jq -r '.[].item2') )

Le JSON que j'ai est la sortie d'une API. Tout ce dont j'avais besoin pour faire des wans était de supprimer l'argument file et |de diriger la sortie de curl vers jq. Fonctionne très bien et a enregistré quelques étapes.

JpaytonWPD
la source
Ce code est en fait un peu bogué. Regardez ce qui se passe si vous avez un élément de résultat de *- il sera remplacé par une liste de fichiers dans votre répertoire actuel.
Charles Duffy
1
De même, une item2valeur contenant un espace deviendrait plus d'un élément de tableau.
Charles Duffy
0

comme alternative simple, regardez l' jtcoutil (à https://github.com/ldn-softdev/jtc ), pour réaliser la même chose (comme dans l'exemple de jq):

bash $ arr=( $(jtc -w '<item2>l+0' file.json) )
bash $ printf '%s\n' "${arr[@]}"
"value2"
"value2_2"
bash $ 

explication sur l' -woption: les parenthèses angulaires <...>spécifient la recherche de json entier, le suffixe lindique de rechercher des étiquettes plutôt que des valeurs, +0indique de trouver toutes les occurrences (plutôt que juste la première).

Dmitry L.
la source
Même bogue que toutes les arr=( $(jq ...) )réponses, dans la mesure où le contenu est divisé en chaînes et étendu par glob pour remplir le tableau - ce qui signifie que les espaces (pas seulement les nouvelles lignes) créent de nouveaux éléments, et les éléments qui ressemblent à une expression de glob sont remplacés par des fichiers qui l'expression correspond.
Charles Duffy