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

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

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

[
  {
    "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 Element2 in einem Array für ein Bash-Skript, das unter Ubuntu 14.04.1 ausgeführt werden soll.

Ich habe eine Reihe von Möglichkeiten gefunden, das gesamte Ergebnis in ein Array zu bekommen, aber nicht nur die Elemente, die ich brauche

Antwort1

Verwenden von:

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

Wenn Sie eine anspruchsvollere Methode benötigen:

readarray -td '' arr

für Eingaben mit Zeilenumbrüchen oder anderen Sonderzeichen, um die Worttrennung zu vermeiden.

Ausgabe:

value2
value2_2

Überprüfen:

Prozesssubstitution >(command ...)oder <(...)wird durch einen temporären Dateinamen ersetzt. Beim Schreiben oder Lesen dieser Datei werden Bytes an den darin enthaltenen Befehl weitergeleitet. Wird oft in Kombination mit Dateiumleitung verwendet: cmd1 2> >(cmd2). Siehehttp://mywiki.wooledge.org/ProcessSubstitution http://mywiki.wooledge.org/BashFAQ/024

Antwort2

Folgendes ist tatsächlich fehlerhaft:

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

Wenn Sie über Bash 4.4 oder neuer verfügen, steht Ihnen die beste Option aller Zeiten zur Verfügung:

# BEST: Supports bash 4.4+, with failure detection and newlines in data
{ readarray -t -d '' arr && wait "$!"; } < <(
  set -o pipefail
  curl --fail -k "$url" | jq -j '.[].item2 | (., "\u0000")'
)

...wohingegen Sie bei Bash 4.0 Kürze auf Kosten der Fehlererkennung und der Unterstützung für wörtliche Zeilenumbrüche erreichen können:

# OK (with bash 4.0), but can't detect failure and doesn't support values with newlines
readarray -t arr < <(curl -k "$url" | jq -r '.[].item2' )

… oder Bash 3.x-Kompatibilität und Fehlererkennung, aber ohne Newline-Unterstützung:

# OK: Supports bash 3.x; no support for newlines in values, but can detect failures
IFS=$'\n' read -r -d '' -a arr < <(
  set -o pipefail
  curl --fail -k "$url" | jq -r '.[].item2' && printf '\0'
)

… oder Bash 3.x-Kompatibilität und Newline-Unterstützung, aber ohne Fehlererkennung:

# OK: Supports bash 3.x and supports newlines in values; does not detect failures
arr=( )
while IFS= read -r -d '' item; do
  arr+=( "$item" )
done < <(curl --fail -k "$url" | jq -j '.[] | (.item2, "\u0000")')

Antwort3

Verwenden Sie es jq, um eine Shell-Anweisung zu erzeugen, die Sie auswerten:

eval "$( jq -r '@sh "arr=( \([.[].item2]) )"' file.json )"

Angesichts des JSON-Dokuments in Ihrer Frage jqwird der Aufruf von die Zeichenfolge erzeugen

arr=( 'value2' 'value2_2' )

welches dann von Ihrer Shell ausgewertet wird. Die Auswertung dieses Strings erzeugt das benannte Array arrmit den beiden Elementen value2und value2_2:

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

Der @shOperator in jqachtet darauf, die Daten für die Shell richtig zu zitieren.

Alternativ können Sie den arr=( ... )Teil aus dem jqAusdruck heraus verschieben:

eval "arr=( $( jq -r '@sh "\([.[].item2])"' file.json ) )"

Jetzt jqwird nur noch die zitierte Liste von Elementen generiert, die dann eingefügt arr=( ... )und ausgewertet wird.

curlWenn Sie Daten aus einem Befehl lesen müssen , verwenden Sie in den obigen Befehlen curl ... | jq -r ...anstelle von .jq -r ... file.json

Antwort4

Dank Sputnick bin ich hierher gekommen:

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

Das JSON, das ich habe, ist die Ausgabe einer API. Ich musste lediglich das Dateiargument entfernen und |die Ausgabe von curl an jq weiterleiten. Funktioniert super und hat einige Schritte gespart.

verwandte Informationen