jq-解析结构并将值保存在bash变量中



我有一个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}"

上述回波命令的预期输出:

4
9
9
0
4
2
echo -e "${a}"

上述回波命令的预期输出:

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

如何使用jq,通过一个jq调用以级联方式循环遍历所有数组来实现这一点?我想通过只调用一次jq并提取所有单个或数组值来节省CPU。

您不能直接从jq设置环境变量(参见手册(。您可以做的是为declare内建生成一系列bash声明。我建议将声明存储在由declare直接处理的中间bash数组(带有mapfile(中,这样您就可以远离像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)的字符串,其中字段名是路径表达式的最后一个组件,即.xx.inner_arr[].aa(在数组的第一项上提取(。

然后可以使用declare -p var${var[@]}检查shell变量。${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