
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 vonjq:
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 jq
wird 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 arr
mit den beiden Elementen value2
und value2_2
:
$ eval "$( jq -r '@sh "arr=( \([.[].item2]) )"' file.json )"
$ printf '"%s"\n' "${arr[@]}"
"value2"
"value2_2"
Der @sh
Operator in jq
achtet darauf, die Daten für die Shell richtig zu zitieren.
Alternativ können Sie den arr=( ... )
Teil aus dem jq
Ausdruck heraus verschieben:
eval "arr=( $( jq -r '@sh "\([.[].item2])"' file.json ) )"
Jetzt jq
wird nur noch die zitierte Liste von Elementen generiert, die dann eingefügt arr=( ... )
und ausgewertet wird.
curl
Wenn 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.