Analysieren Sie ein Feld aus einem JSON-Array in ein Bash-Array

12

Ich habe eine JSON-Ausgabe, die eine Liste von Objekten enthält, die in einer Variablen gespeichert sind. (Ich kann das nicht richtig formulieren)

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

Ich benötige alle Werte für item2 in einem Array, damit ein Bash-Skript unter Ubuntu 14.04.1 ausgeführt werden kann.

Ich habe eine Reihe von Möglichkeiten gefunden, um das gesamte Ergebnis in ein Array zu integrieren, aber nicht nur die Elemente, die ich benötige

JpaytonWPD
quelle

Antworten:

16

Mit :

$ 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[@]}"

AUSGABE:

value2
value2_2
Gilles Quenot
quelle
Ist es möglich, dies von einer Variablen anstelle einer Datei aus zu tun? Ich versuche, übermäßigen Zugriff auf das Dateisystem zu vermeiden, wenn ich ihn nicht benötige. Sobald ich dieses Array gezogen habe, bin ich mit der JSON-Ausgabe fertig.
JpaytonWPD
1
Hast du etwas ausprobiert?
Gilles Quenot
2
jq . <<< "$json"Es ist Shell (Bash) bezogen, nicht spezifisch fürjq
Gilles Quenot
1
Fehlende Klammern:arr=( $(...) )
Gilles Quenot
3
Großartiger jqBefehl, aber bitte analysieren Sie die Befehlsausgabe nicht in ein Array mit arr=( $(...) )(obwohl dies zufällig mit der Beispieleingabe funktioniert): Es funktioniert nicht wie beabsichtigt mit eingebetteten oder führenden / nachfolgenden Leerzeichen und kann zu versehentlichem Globbing führen.
mklement0
4

Folgendes ist eigentlich fehlerhaft:

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

Verwenden Sie stattdessen:

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

... oder noch besser ...

# 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
quelle
2

Dank Sputnick bin ich dazu gekommen:

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

Der JSON, den ich habe, ist die Ausgabe einer API. Alles, was ich tun musste, war, das Dateiargument zu entfernen und |die Ausgabe von curl an jq weiterzuleiten. Funktioniert super und hat einige Schritte gespart.

JpaytonWPD
quelle
Dieser Code ist eigentlich ein bisschen fehlerhaft. Sehen Sie sich an, was passiert, wenn Sie ein Ergebniselement von haben *- es wird durch eine Liste von Dateien in Ihrem aktuellen Verzeichnis ersetzt.
Charles Duffy
1
In ähnlicher Weise würde ein item2Wert mit Leerzeichen mehr als ein Array-Element werden.
Charles Duffy
0

Schauen Sie sich als einfache Alternative das jtcTool (unter https://github.com/ldn-softdev/jtc ) an, um dasselbe zu erreichen (wie im Beispiel von jq):

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

Erklärung zur -wOption: Winkelklammern <...>geben die Suche im gesamten JSON an, das Suffix lweist an, Beschriftungen anstelle von Werten +0zu suchen , und weist an, alle Vorkommen zu finden (und nicht nur das erste).

Dmitry L.
quelle
Gleicher Fehler wie alle arr=( $(jq ...) )Antworten, sofern der Inhalt zum Auffüllen des Arrays durch Zeichenfolgen geteilt und glob erweitert wird. Das bedeutet, dass Leerzeichen (nicht nur Zeilenumbrüche) neue Elemente erstellen und Elemente, die wie ein Glob-Ausdruck aussehen, durch Dateien ersetzt werden, die Ausdruck stimmt überein.
Charles Duffy