it-swarm.com.de

JSON-Array zum Bash-Variablen mit jq

Ich habe ein JSON-Array wie folgt:

{
  "SITE_DATA": {
    "URL": "example.com",
    "AUTHOR": "John Doe",
    "CREATED": "10/22/2017"
  }
}

Ich möchte dieses Array mit jq durchlaufen, damit ich den Schlüssel jedes Elements als Variablennamen und den Wert als Wert festlegen kann.

Beispiel:

  • URL = "example.com"
  • AUTOR = "John Doe"
  • CREATED = "22.10.2017"

Was ich bisher habe, iteriert über das Array, erstellt aber einen String:

constants=$(cat ${1} | jq '.SITE_DATA' | jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]")

Welche Ausgänge:

URL=example.com
AUTHOR=John Doe
CREATED=10/22/2017

Ich möchte diese Variablen weiter unten im Skript verwenden:

echo ${URL}

Dies spiegelt jedoch im Moment eine leere Ausgabe wider. Ich schätze, ich brauche ein eval oder etwas drin, kann aber nicht meinen Finger darauf legen.

19
EHerman

Ihre ursprüngliche Version ist nicht evalable, da der Autorenname Leerzeichen enthält. Sie wird so interpretiert, dass ein Befehl Doe mit der Umgebungsvariablen AUTHOR ausgeführt wird John. Es besteht auch praktisch nie die Notwendigkeit, jq an sich selbst weiterzuleiten - das internes Piping & Datenfluss kann verschiedene Filter miteinander verbinden.

Sie können eine viel einfachere Version des jq-Programms erstellen:

jq -r '.SITE_DATA | to_entries | .[] | .key + "=\"" + .value + "\""'

welche Ausgänge:

URL="example.com"
AUTHOR="John Doe"
CREATED="10/22/2017"

Es ist kein map erforderlich: .[] Behandelt jedes Objekt im Array als separates Element durch den Rest der Pipeline , also alles nach dem letzten | Wird für jeden einzeln angewendet. Am Ende stellen wir einfach eine gültige Shell-Zuweisungszeichenfolge mit normaler + - Verkettung zusammen, einschließlich Anführungszeichen um den Wert.

Alle Pipes spielen hier eine Rolle - ohne sie erhalten Sie ziemlich wenig hilfreiche Fehlermeldungen, bei denen Teile des Programms in subtil unterschiedlichen Kontexten ausgewertet werden.

Diese Zeichenfolge ist evalable, solange die Zeichen `, $, Newline und null nicht in den Daten enthalten sind:

eval "$(jq -r '.SITE_DATA | to_entries | .[] | .key + "=\"" + .value + "\""' < data.json)"
echo "$AUTHOR"

Achten Sie wie immer bei der Verwendung von eval darauf, dass Sie den Daten vertrauen, die Sie erhalten, da bei einem böswilligen oder nur unerwarteten Format möglicherweise Fehler auftreten können.

29
Michael Homer

Aufbauend auf der Antwort von @Michael Homer können Sie ein potenziell unsicheres eval vollständig vermeiden, indem Sie die Daten in ein assoziatives Array einlesen.

Wenn sich Ihre JSON-Daten beispielsweise in einer Datei mit dem Namen file.json Befinden:

#!/bin/bash

typeset -A myarray

while IFS== read -r key value; do
    myarray["$key"]="$value"
done < <(jq -r '.SITE_DATA | to_entries | .[] | .key + "=" + .value ' file.json)

# show the array definition
typeset -p myarray

# make use of the array variables
echo "URL = '${myarray[URL]}'"
echo "CREATED = '${myarray[CREATED]}'"
echo "AUTHOR = '${myarray[URL]}'"

Ausgabe:

$ ./read-into-array.sh 
declare -A myarray=([CREATED]="10/22/2017" [AUTHOR]="John Doe" [URL]="example.com" )
URL = 'example.com'
CREATED = '10/22/2017'
AUTHOR = 'example.com'
13
cas

Ich habe gerade festgestellt, dass ich die Ergebnisse durchlaufen und jede Iteration bewerten kann:

constants=$(cat ${1} | jq '.SITE_DATA' | jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]")

for key in ${constants}; do
  eval ${key}
done

Erlaubt mir:

echo ${AUTHOR}
# outputs John Doe
1
EHerman

Ich mag den @ Michael-Vorschlag sehr. Manchmal können Sie wirklich nur einen Variablenwert extrahieren, um eine Aufgabe auf diesem bestimmten Server mit BASH auszuführen. Gewünschte Variablen sind also bekannt. Mit diesem Ansatz können Sie mehrere Aufrufe von jq vermeiden, um einen Wert pro Variable festzulegen, oder sogar die read-Anweisung mit mehreren Variablen verwenden, von denen einige gültig und leer sein können, was zu einer Wertverschiebung führt (das war mein Problem).

mein vorheriger Ansatz, der dazu führt, führt zu einem Wertverschiebungsfehler, wenn .svID [] .ID = "" ( sv das slotID value

-rd '\n' getInfo sv slotID <<< $(jq -r '(.infoCMD // "no info"), (.svID[].ID // "none"), (._id // "eeeeee")' <<< $data)

Wenn Sie das Objekt mit curl heruntergeladen haben, ist hier mein Ansatz, einige Variablen in einen Anzeigenamen umzubenennen, um Daten aus Datenarrays zu extrahieren

Die Verwendung von eval und filter löst das Problem mit einer Zeile und erzeugt Variablen mit dem gewünschten Namen

eval "$(jq -r '.[0] | {varNameExactasJson, renamedVar1: .var1toBeRenamed, varfromArray: .array[0].var, varValueFilter: (.array[0].textVar|ascii_downcase)} | to_entries | .[] | .key + "=\"" + (.value | tostring) + "\""' <<< /path/to/file/with/object )"  

Der Vorteil in diesem Fall ist die Tatsache, dass im ersten Schritt alle gewünschten Variablen gefiltert, umbenannt und formatiert werden. Beachten Sie, dass dort drin ist. [0] | Dies ist sehr häufig der Fall, wenn die Quelle von einem RESTFULL-API-Server mit GET Antwortdaten wie folgt enthält:

[{"varNameExactasJson":"this value", "var1toBeRenamed: 1500, ....}]

Wenn Ihre Daten nicht aus einem Array stammen, z. ist ein Objekt wie:

{"varNameExactasJson":"this value", "var1toBeRenamed: 1500, ....}

entfernen Sie einfach den Anfangsindex:

eval "$(jq -r '{varNameExactasJson, renamedVar1: .var1toBeRenamed, varfromArray: .array[0].var, varValueFilter: (.array[0].textVar|ascii_downcase)} | to_entries | .[] | .key + "=\"" + (.value | tostring) + "\""' <<< /path/to/file/with/object )"  

Dies ist eine alte Frage, aber ich fühlte mich geteilt, da es schwer zu finden war

0
Thiago Conrado