analizzare un campo da un array JSON in un array bash


13

Ho un output JSON che contiene un elenco di oggetti memorizzati in una variabile. (Forse non sto esprimendo questo diritto)

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

Ho bisogno di tutti i valori di item2 in un array affinché uno script bash possa essere eseguito su Ubuntu 14.04.1.

Ho trovato un sacco di modi per ottenere l'intero risultato in un array, ma non solo gli elementi di cui ho bisogno

Risposte:


17

Utilizzando :

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

CODICE:

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

PRODUZIONE:

value2
value2_2

È possibile farlo da una variabile anziché da un file? Cerco di evitare un eccesso di accesso al filesystem se non ne ho bisogno. Una volta estratto questo array, ho finito con l'output json.
JpaytonWPD

1
Hai provato qualcosa?
Gilles Quenot

2
jq . <<< "$json"è correlato alla shell (bash), non specifico perjq
Gilles Quenot

1
Parentesi mancanti:arr=( $(...) )
Gilles Quenot

4
Ottimo jqcomando, ma per favore non analizzare l'output del comando in un array con arr=( $(...) )(anche se funziona con l'input di esempio): non funziona come previsto con gli spazi bianchi incorporati o in testa / in coda e può provocare un travaglio accidentale.
mklement0

5

Quanto segue è in realtà buggy:

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

Invece, usa:

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

... o meglio ancora ...

# 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')

2

Grazie a Sputnick sono arrivato a questo:

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

Il JSON che ho è l'output di un'API. Tutto ciò di cui avevo bisogno per fare wans rimuovere l'argomento file e reindirizzare |l'output di curl a jq. Funziona alla grande e ha salvato alcuni passaggi.


Quel codice è in realtà un po 'difettoso. Guarda cosa succede se si dispone di un elemento risultato di *: verrà sostituito con un elenco di file nella directory corrente.
Charles Duffy,

1
Allo stesso modo, un item2valore con spazi bianchi diventerebbe più di un elemento array.
Charles Duffy,

0

come alternativa semplice, guarda lo jtcstrumento (su https://github.com/ldn-softdev/jtc ), per ottenere la stessa cosa (come nell'esempio di jq):

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

spiegazione -wsull'opzione: le parentesi angolari <...>specificano la ricerca intera json, il suffisso lindica di cercare le etichette anziché i valori, +0indica di trovare tutte le occorrenze (anziché solo la prima).


Stesso bug di tutte le arr=( $(jq ...) )risposte, nella misura in cui i contenuti vengono suddivisi in stringhe ed espansi glob per popolare l'array - il che significa che gli spazi (non solo le nuove linee) creano nuovi elementi e gli elementi che sembrano un'espressione glob vengono sostituiti da file che corrispondenze di espressione.
Charles Duffy,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.