简介

jq 命令是一个轻量且灵活的命令行 JSON 处理器,可以方便快捷地解析 JSON 格式的数据。

基本用法

解析 JSON 格式的数据

1
cat task_feature_file | jq .

根据 key 获取 value

1
cat task_feature_file | jq '.cms_data'

根据 key 获取 value(嵌套提取)

1
cat task_feature_file | jq '.cms_data.res_id'

提取所有 key

1
cat task_feature_file | jq 'keys'

提取所有 key(嵌套提取)

1
cat task_feature_file | jq '.cms_data' | jq 'keys'

判断是否有某个 key

1
cat task_feature_file | jq 'has("cms_data")'

数据转换

转换数字为字符串

1
2
3
4
5
6
7
jq -r '.[] | [ .string, .number|tostring ] | join(": ")' <<< '
[{ "number": 9, "string": "nine"},
{ "number": 4, "string": "four"}]
'
# 输出:
# nine: 9
# four: 4

转换 JSON 对象为 key=value 形式

方法 1:

1
jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" test.json

示例:

1
2
3
4
5
6
7
8
9
10
11
12
$ cat test.json
{
"var": 1,
"foo": "bar",
"x": "test"
}

$ jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" test.json
# 输出:
# foo=bar
# var=1
# x=test

方法 2:

1
jq -r '.SITE_DATA | to_entries | .[] | .key + "=\"" + .value + "\""' data.json

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
$ cat data.json
{
"SITE_DATA": {
"URL": "example.com",
"AUTHOR": "John Doe",
"CREATED": "10/22/2017"
}
}

# 输出:
# URL="example.com"
# AUTHOR="John Doe"
# CREATED="10/22/2017"

这种格式可以直接使用 eval 命令:

1
2
eval "$(jq -r '.SITE_DATA | to_entries | .[] | .key + "=\"" + .value + "\""' < data.json)"
echo "$AUTHOR"

方法 3:循环遍历

1
2
3
4
5
6
7
constants=$(cat ${1} | jq '.SITE_DATA' | jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]")
for key in ${constants}; do
eval ${key}
done

echo ${AUTHOR}
# 输出:John Doe

输出格式控制

将输出压缩为一行

使用 -c 参数:

1
jq -c . input

输出示例:

1
2
{"key":"SEA-739","status":"Open","assignee":null}
{"key":"SEA-738","status":"Resolved","assignee":"user2@mycompany.com"}

或者在原命令中使用 -c 替换 -r

1
jq -c '(.issues[] | {key, status: .fields.status.name, assignee: .fields.assignee.emailAddress})'

数组处理

JSON 数组转 Bash 数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
$ cat json
[
{
"item1": "value1",
"item2": "value2",
"sub items": [
{
"subitem": "subvalue"
}
]
},
{
"item1": "value1_2",
"item2": "value2_2",
"sub items_2": [
{
"subitem_2": "subvalue_2"
}
]
}
]

代码:

1
2
arr=( $(jq -r '.[].item2' json) )
printf '%s\n' "${arr[@]}"

输出:

1
2
value2
value2_2

遍历 JSON 数组

示例数据:

1
2
sample='[{"name":"foo"},{"name":"bar"}]'  
echo "${sample}" | jq '.'

使用 jq --compact-output (或 -c) 可以将每个对象输出为一行:

1
2
sample='[{"name":"foo"},{"name":"bar"}]'  
echo "${sample}" | jq -c '.[]'

输出:

1
2
{"name":"foo"}
{"name":"bar"}

如果数据包含空格或换行符,可以使用 base64 编码:

1
2
sample='[{"name":"foo"},{"name":"bar"}]'  
echo "${sample}" | jq -r '.[] | @base64'

输出:

1
2
eyJuYW1lIjoiZm9vIn0=  
eyJuYW1lIjoiYmFyIn0=

使用 for 循环遍历:

1
2
3
4
5
6
7
sample='[{"name":"foo"},{"name":"bar"}]'  
for row in $(echo "${sample}" | jq -r '.[] | @base64'); do
_jq() {
echo ${row} | base64 --decode | jq -r ${1}
}
echo $(_jq '.name')
done

输出:

1
2
foo
bar

实例:

1
2
3
4
5
6
7
cat test.json | jq -c -r ".[] | {status : .status}" | while read row
do
_jq() {
echo ${row} | jq -r ${1}
}
echo $(_jq '.status')
done

以上代码等同于:

1
2
3
4
5
6
7
cat test.json | jq -r ".[] | {status: .status} | @base64"  | while read row
do
_jq() {
echo ${row} | base64 --decode | jq -r ${1}
}
echo $(_jq '.status')
done

常见问题

解决报错:parse error: Invalid string: control characters from U+0000 through U+001F must be escaped

这个错误通常是因为 jq 1.5 版本不支持 JSON 中的换行符。解决方法:

1
2
3
4
5
# 用空格替换换行符
json_string=$(echo ${string} | tr '\r\n' ' ')

# 或者直接删除换行符
json_string=$(echo ${string} | tr -d '\r\n')

通过 tr 函数做替换即可解决问题。