
Я работаю с данными о местоположении и запрашиваю API с почтовыми индексами США и возвращаю следующий результат:
{
"resultStatus":"SUCCESS",
"zip5":"30301",
"defaultCity":"ATLANTA",
"defaultState":"GA",
"defaultRecordType":"PO BOX",
"citiesList":[],
"nonAcceptList":[{"city":"ATL","state":"GA"}]
}
Мне нужно проанализировать это, чтобы создать вывод, который также включает полное название штата, например:
ATLANTA, Georgia, GA, 30301
Я создал ассоциативный массив под названием States, который ${States[GA]}
будет возвращать значение Georgia
, и попытался передать массив в jq в качестве аргумента, например:
curl -sS <enpoint> |jq -r '"${States[\(.defaultState)]}, \(.defaultState), \(.defaultCity), \(.zip5)"'
Что привело к выходу${States[GA]}, GA, ATLANTA, 30301
Есть ли способ передать и оценить массивы bash в фильтрах jq или подобных?
Единственный вариант, который я вижу, — это перехватить вывод и передать его через eval, но, конечно, eval — это зло... Я также собираюсь делать это тысячи раз и комбинировать с другими внешними данными из файла, поэтому я бы предпочел лучший вариант, чем создание запутанных строк со встроенными аргументами bash и их вычисление.
РЕДАКТИРОВАТЬ
Забыл упомянуть, что я пробовал поискjq 1.6 руководствобез удачи и нашел этоSO Постчто привело меня к попытке передать массив States как аргумент jq следующим образом:
curl -sS <enpoint> |jq -r --arg states $States '"$states[\(.defaultState)], \(.defaultState), \(.defaultCity), \(.zip5)"'
но все равно безуспешно.
Работоспособный сценарий, реализующий ответ 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
решение1
Если вы можете превратить массив bash в допустимый объект JSON, то (с небольшими изменениями в интерполяции строк) вы можете передать его с помощью --argjson
. Например, учитывая
$ declare -p States
declare -A States=([GA]="Georgia" [NY]="New York" [ME]="Maine" )
затем ссылаясь на
затем
$ 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"
}
так что
$ 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