jq - разобрать структуру и сохранить значения в bash переменной - PullRequest
1 голос
/ 07 мая 2020

У меня есть json ввод, как показано ниже

{
  "unique": 1924,
  "coordinates": [
    {
      "time": "2015-01-25T00:00:01.683",
      "xyz": [
        {
          "z": 4,
          "y": 2,
          "x": 1,
          "id": 99,
          "inner_arr" : [
          {
              "a": 1,
              "b": 2
          },
          {
              "a": 3,
              "b": 4
          }
          ]
        },
        {
          "z": 9,
          "y": 9,
          "x": 8,
          "id": 100,
          "inner_arr" : [
          {
              "a": 1,
              "b": 2
          },
          {
              "a": 3,
              "b": 4
          }
          ]
        },
        {
          "z": 9,
          "y": 6,
          "x": 10,
          "id": 101,
          "inner_arr" : [
          {
              "a": 1,
              "b": 2
          },
          {
              "a": 3,
              "b": 4
          }
          ]
        }
      ]
    },
    {
      "time": "2015-01-25T00:00:02.790",
      "xyz": [
        {
          "z": 0,
          "y": 3,
          "x": 7,
          "id": 99,
         "inner_arr" : [
          {
              "a": 1,
              "b": 2
          },
          {
              "a": 3,
              "b": 4
          }
          ]
        },
        {
          "z": 4,
          "y": 6,
          "x": 2,
          "id": 100,
          "inner_arr" : [
          {
              "a": 1,
              "b": 2
          },
          {
              "a": 3,
              "b": 4
          }
          ]
        },
        {
          "z": 2,
          "y": 9,
          "x": 51,
          "id": 101,
          "inner_arr" : [
          {
              "a": 1,
              "b": 2
          },
          {
              "a": 3,
              "b": 4
          }
          ]
        }
      ]
    }
  ]
}

Я хочу проанализировать этот ввод с помощью jq и сохранить значения в bash массивах:

#!/bin/bash

z=()
x=()
y=()
id=()
a=()
b=()

jq --raw-output '.coordinates[] | .xyz[] | (.z) as $z, (.y) as $y,7 (.x) as $x, (.id) as $id, .inner_arr[].a $a, .inner_arr[].b as $b | $z, $y, $x, $id, $a, $b' <<< "$input"


echo -e "${z}"

Ожидаемый результат для приведенная выше команда echo:

4
9
9
0
4
2

echo -e "${a}"

Ожидаемый результат для указанной выше команды echo:

1
3
1
3
1
3
1
3
1
3
1
3

Как я могу сделать это с помощью jq с одним вызовом jq, проходящим через все массивы каскадным образом? Я хочу сэкономить процессор, вызывая jq только один раз и извлекая все одиночные значения или значения массива.

1 Ответ

2 голосов
/ 08 мая 2020

Вы не можете установить переменную среды напрямую из jq (см. manual ). Что вы можете сделать, так это создать серию объявлений bash для встроенной declare. Я предлагаю хранить объявления в промежуточном массиве bash (с mapfile), обрабатываемым непосредственно declare, чтобы вы могли держаться подальше от опасных команд, таких как eval.

mapfile -t < <(
    jq --raw-output '
        def m(exp): first(.[0] | path(exp)[-1]) + "=(" + (map(exp) | @sh) + ")";
        [ .coordinates[].xyz[] ]
        | m(.x), m(.y), m(.z), m(.id), m(.inner_arr[].a), m(.inner_arr[].b)
    ' input
)

declare -a "${MAPFILE[@]}"

jq скрипт упаковывает все объекты xyz в один массив и фильтрует его с помощью функции m для каждого поля, представленного в виде выражения пути. Функция возвращает строку, отформатированную как field=(val1 val2... valN), где имя поля является последним компонентом выражения пути, т.е. x для .x и a для .inner_arr[].a (извлечено по первому элементу массива) .

Затем вы можете проверить переменные оболочки с помощью declare -p var или ${var[@]}. ${var} относится только к первому элементу.

declare -p MAPFILE
declare -p z
echo a: "${a[@]}" / size = ${#a[@]}

declare -a MAPFILE=([0]="x=(1 8 10 7 2 51)" [1]="y=(2 9 6 3 6 9)" [2]="z=(4 9 9 0 4 2)" [3]="id=(99 100 101 99 100 101)" [4]="a=(1 3 1 3 1 3 1 3 1 3 1 3)" [5]="b=(2 4 2 4 2 4 2 4 2 4 2 4)")
declare -a z=([0]="4" [1]="9" [2]="9" [3]="0" [4]="4" [5]="2")
a: 1 3 1 3 1 3 1 3 1 3 1 3 / size = 12
...