1

I have a json input as follow

{
  "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
          }
          ]
        }
      ]
    }
  ]
}

I want to parse this input with jq and store values in bash arrays:

#!/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}"

Expected output for above echo command:

4
9
9
0
4
2

echo -e "${a}"

Expected output for above echo command:

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

How can I do it with jq with a single jq call looping through all arrays in a cascading fashion? I want to save CPU by calling jq just once and extract all single or array values.

1 Answer 1

3

You cannot set environment variable directly from jq (cf. manual). What you can do is to generate a series of bash declarations for the declare builtin. I suggest to store the declarations in an intermediate bash array (with mapfile) processed directly by declare so that you can stay away from hazardous commands like 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[@]}"

The jq script packs all xyz objects in a single array and filters it with the m function for each field represented as a path expression. The function returns a string formatted as field=(val1 val2... valN), where the field name is the last component of the path expression, i.e. x for .x and a for .inner_arr[].a (extracted on the first item of the array).

Then you can check the shell variables with declare -p var or ${var[@]}. ${var} refers to the first element only.

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
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.