日常编写 bash 脚本处理 json 时,我们大概率会使用 jq 这个工具,此时我们需要学习一些 jq 的语法,下面总结一些使用过程中遇到的一些问题和解决方式。
使用 bash 变量
$ var1="hello"
$ jq --arg var1 $var1 '.res[$var1]' filename.json
可以多次使用--arg inner_var bash_var
的方式。
检查 key 是否存在
$ jq -r '.result | has("keyname")' filename.json
true # or false
检查字段是否存在某些字段
$ jq -r '.result.var | contains("content")' filename.json
true # or false
获取 object 的 key 或者 value
比如有如下的 json :
{
"key1": {
"key11": {
"key111": {
"key1111": "hello"
}
}
},
"key2": {
"key22": {
"key222": {
"key2222": "world"
}
}
}
}
若只想输入两个 value 的值,hello
和world
。 可以用的方式是:
$ jq -r '.[] | .[] | .[] | to_entries | .[].value' xxx.json
hello
world
注意这边的to_entries
是将内容转变成固定格式:
[
{
"key": "key111",
"value": {
"key1111": "hello"
}
}
]
[
{
"key": "key222",
"value": {
"key2222": "world"
}
}
]
之后再统一取指定的 key 下面的内容。
jq 读取 array 内容到 bash 变量
我们经常需要将 json 的数组内容读取到 bash 的数组中。可以有两种方式,主要看 bash 的版本:
bash 4+
$ mapfile -t arr < <(jq -r 'keys[]' xxx.json)
older bash
arr=()
while IFS='' read -r line; do
arr+=("$line")
done < <(jq 'keys[]' xxx.json)
此外还有一种方式用于纯 json 数组的转换,比如:
#[
# 1, 2, 3, 4, 5, 6, 7, 8, 9
#]
$ arr=($(jq -r '. | @sh' xxx.json))
@sh: The input is escaped suitable for use in a command-line for a POSIX shell. If the input is an array, the output will be a series of space-separated strings.
jq 输出多字段内容读取到 bash 变量中
当我们同时需要读取两个并列的 json 字段的内容到脚本中同时处理时,这个过程稍微有点复杂。
jq -r '. | [.name,.value] | @tsv' model_info.json | \
while IFS=$'\t' read -r name ctx; do
echo $name, $ctx
done
@tsv: The input must be an array, and it is rendered as TSV (tab-separated values). Each input array will be printed as a single line. Fields are separated by a single tab (ascii 0x09). Input characters line-feed (ascii 0x0a), carriage-return (ascii 0x0d), tab (ascii 0x09) and backslash (ascii 0x5c) will be output as escape sequences \n, \r, \t, \ respectively.
总体的思路就是先转成 tsv 格式,后续在 read 指定分隔符读取。
join 指定字段内容
join 是使用指定分隔符去合并相应的数组内容,比如有数组:[1,2,3,4,5]
$ jq -r '.|join("|")' arr.json
1|2|3|4|5