Преобразование ответа JSON в пару ключ-значение с использованием jq - PullRequest
0 голосов
/ 13 февраля 2020

Итак, я получаю ответ от API, который я вызываю в сценарии оболочки, в следующей форме

[{"id":100000004,"name":"Customs Clearance Requested"},{"id":100000005,"name":"Customs Cleared"},{"id":100000006,"name":"Cargo Loaded to Vessel"}]

Я хочу создать из него карту, которая поможет мне найти идентификатор от имени и использовать его в сценарии оболочки. Таким образом, что-то вроде карты [«Требуется таможенная очистка»] дало бы мне 100000004, что я могу использовать в дальнейшем. Можно ли это сделать с помощью jq? Я довольно новичок в сценариях оболочки и jq и застрял с вышеупомянутой вещью

Ответы [ 3 ]

3 голосов
/ 13 февраля 2020
json='[{"id":100000004,"name":"Customs Clearance Requested"},{"id":100000005,"name":"Customs Cleared"},{"id":100000006,"name":"Cargo Loaded to Vessel"}]'

declare -A map
while IFS= read -r -d '' name && IFS= read -r -d '' value; do
  map[$name]=$value
done < <(jq -j '.[] | "\(.name)\u0000\(.id)\u0000"' <<<"$json")

declare -p map  # demo purposes: print the map we created as output

... выводится как вывод:

declare -A map=(["Cargo Loaded to Vessel"]="100000006" ["Customs Clearance Requested"]="100000004" ["Customs Cleared"]="100000005" )

... который вы можете запросить точно так, как запрошено:

$ echo "${map['Cargo Loaded to Vessel']}"
100000006
0 голосов
/ 13 февраля 2020

Следующее очень похоже на отличный ответ @ CharlesDuffy, но не предполагает, что значения .name и .id не имеют значения NUL (т. Е. Не имеют символов "\ u0000"):

declare -A map
while read -r name
do
    name=$(sed -e 's/^"//' -e 's/"$//' <<< "$name")
    read -r id
    map[$name]="$id"
done < <(echo "$json" | jq -c '.[]|.name,.id')

Дело в том, что опция -j похожа на -r (т. Е. Производит «необработанный вывод»), а опция - c выдает JSON.

Это означает, что если вы не хотите, чтобы значения .id были строками JSON, то вышеприведенное не будет решением; Кроме того, если значения .name содержат двойные кавычки, вы можете иметь дело с вхождениями \".

0 голосов
/ 13 февраля 2020

Вы можете использовать функцию select, например:

data='[{"id":100000004,"name":"Customs Clearance Requested"},{"id":100000005,"name":"Customs Cleared"},{"id":100000006,"name":"Cargo Loaded to Vessel"}]'
jq 'map(select(.["name"] == "Customs Clearance Requested"))' <<< $data

Она получит все элементы, которым name равно "Customs Clearance Requested", например:

[
  {
    "id": 100000004,
    "name": "Customs Clearance Requested"
  }
]

Если вы хотите получить поле id :

jq 'map(select(.["name"] == "Customs Clearance Requested")["id"])' <<< $data

Это выдаст:

[
  100000004
]

Обратите внимание, что оно будет вернуть массив , а не один элемент, потому что поиск не знает, сколько результатов будет найдено.

Если вы хотите обобщить это в функции оболочки, вы можете написать:

function get_id_from_name
{
  # $1=name to search for
  local filter=$(printf 'map(select(.["name"] == "%s")["id"])' "$1")
  jq "$filter"
}

Затем назовите это так:

get_id_from_name "Customs Clearance Requested" <<< $data

Если ваши данные хранятся в файле, вы можете назвать это так:

get_id_from_name "Customs Clearance Requested" < /path/to/file.json

...