
Ich arbeite mit einigen Standortdaten und frage eine API mit US-Postleitzahlen ab. Das Ergebnis lautet wie folgt:
{
"resultStatus":"SUCCESS",
"zip5":"30301",
"defaultCity":"ATLANTA",
"defaultState":"GA",
"defaultRecordType":"PO BOX",
"citiesList":[],
"nonAcceptList":[{"city":"ATL","state":"GA"}]
}
Ich muss dies analysieren, um eine Ausgabe zu erstellen, die auch den vollständigen Statusnamen enthält, etwa:
ATLANTA, Georgia, GA, 30301
Ich habe ein assoziatives Array mit dem Namen „States“ erstellt, damit ${States[GA]}
der Wert zurückgegeben wird Georgia
, und habe versucht, das Array als Argument an jq zu übergeben, wie:
curl -sS <enpoint> |jq -r '"${States[\(.defaultState)]}, \(.defaultState), \(.defaultCity), \(.zip5)"'
Das Ergebnis war die Ausgabe${States[GA]}, GA, ATLANTA, 30301
Gibt es eine Möglichkeit, Bash-Arrays in JQ-Filtern oder Ähnlichem zu übergeben und auszuwerten?
Die einzige Option, die ich sehe, besteht darin, die Ausgabe zu erfassen und durch eval zu leiten, aber eval ist natürlich böse ... Ich werde dies außerdem tausende Male tun und mit anderen externen Daten aus einer Datei kombinieren, daher würde ich eine bessere Option bevorzugen, als verschlungene Zeichenfolgen mit eingebetteten Bash-Argumenten zu konstruieren und sie auszuwerten.
BEARBEITEN
Ich habe vergessen zu erwähnen, dass ich die Suche versucht habejq 1.6 Handbuchohne Glück und fand diesSO Beitragwas mich dazu brachte, zu versuchen, das States-Array als jq-Argument zu übergeben, wie folgt:
curl -sS <enpoint> |jq -r --arg states $States '"$states[\(.defaultState)], \(.defaultState), \(.defaultCity), \(.zip5)"'
aber immer noch kein Glück.
Funktionsfähiges Skript zur Implementierung der Antwort von Steeldrivers:
#! /bin/bash
# Do once and save
statesJson=$(for state in "${!StatesArray[@]}"; do
printf '{"name":"%s",\n"value":"%s"}\n' $state "${StatesArray[$state]}";
done \
| jq -s 'reduce .[] as $i ({}; .[$i.name] = $i.value)');
# Read zip and 6 other values from SourceDataFile.csv
while IFS=',' read -r zip fileValue02 fileValue03 fileValue04 fileValue05 fileValue06 fileValue07; do
# Use zip from file to get expanded location data.
expandedLocationData=$(curl -sS '<apiEndpoint>' -H <Headers> --data "zip=$zip" |jq -r --argjson states "${statesJson}" '"\United States, US, ($states[.defaultState]), \(.defaultState), \(.defaultCity), \(.zip5)"');
# Do useful things with the completed data set.
echo "${expandedLocationData}, ${fileValue02} ${fileValue03}, ${fileValue04}, ${fileValue05}, ${fileValue06}, ${fileValue07}" > ./DestinationDataFile.csv
done < ./SourceDataFile.csv
Antwort1
Wenn Sie das Bash-Array in ein gültiges JSON-Objekt umwandeln können, können Sie es (mit geringfügigen Änderungen an der Zeichenfolgeninterpolation) mit übergeben --argjson
. Beispielsweise bei
$ declare -p States
declare -A States=([GA]="Georgia" [NY]="New York" [ME]="Maine" )
dann unter Bezugnahme auf
Dann
$ for k in "${!States[@]}"; do printf '{"name":"%s",\n"value":"%s"}\n' $k "${States[$k]}"; done | jq -s 'reduce .[] as $i ({}; .[$i.name] = $i.value)'
{
"GA": "Georgia",
"NY": "New York",
"ME": "Maine"
}
so dass
$ jq -r --argjson states \
"$(for k in "${!States[@]}"; do printf '{"name":"%s",\n"value":"%s"}\n' $k "${States[$k]}"; done | jq -s 'reduce .[] as $i ({}; .[$i.name] = $i.value)')" \
'"\($states[.defaultState]), \(.defaultState), \(.defaultCity), \(.zip5)"' file.json
Georgia, GA, ATLANTA, 30301