「jq」- 在 Shell 中,处理 JSON 数据

  CREATED BY JENKINSBOT

问题描述

我们需要在 Shell 中处理 JSON 数据,比如我们请求某个 HTTP 接口,接口返回 JSON 数据,而我们需要从中提取某个字段。当然,我们可以使用 sed grep awk 这些工具,但是这些工具只能进行简单处理。如果我们想要生成结构化数据,这些工具是不够的。我们需要处理 JSON 的专用工具。

经过 Google 查找 jq(stedolan/jq: Command-line JSON processor),用于处理 JSON 数据的 Shell 命令行工具。

该笔记将记录:在 Shell 中,如何使用 jq 命令处理 JSON 数据,以及常见问题处理。

解决方案

安装命令

通过包管理器安装。很多 Linux 发行版中都带有该工具:

# Ubuntu 18.04 LTS
apt-get install -y jq

或者,使用源码编译安装,详细的安装过程,参考 jq/README.md at master · stedolan/jq 文件。这里简单记录:

git submodule update --init # if building from git to get oniguruma (正则表达式库)
autoreconf -fi              # if building from git
./configure --with-oniguruma=builtin
make -j8
make check

常见示例

判断某个 KEY 是否存在。比如,判断在 result 下,是否存在 .property_history 字段(KEY),存在则取其值:

jq '.result | select(.property_history != null) | .property_history'

判断字段的值是否以某个字符串开始:

jq -r '.[]|select(.hostname | startswith("abcd"))' jjjj.json

# 判断是否包含某个字符串
jq -r '.[]|select(.hostname | contains("abcd"))' jjjj.json

修改 JSON 内容:

jq '.clusters[].name = 1231231 | .users[].name = 123456' config.json

传递变量:

jq --arg user "$SOME_USER" '.something.user|="\($user) did a thing"'

场景:输出自定义文本、字符串拼接(输出可执行的命令)

Concat 2 fields in JSON using jq – Stack Overflow

我们希望 jq 可以输出可以执行的 Shell 命令,这里就涉及字符串拼接:

echo '{"channel": "youtube", "profile_type": "video", "member_key": "hello"}' \
 | jq '{channel: (.profile_type + "." + .channel)}'

如上示例,像某些编程语言,使用 + 进行字符串拼接。

场景:将输出作为命令参数(执行命令)

Using jq with bash to run command for each object in array – Stack Overflow

如下示例,将输出使用 TAB 分割字段,再传入 read 命令,便可在命令中直接使用

jq -r '.[]|[.user, .date, .email] | @tsv' |
  while IFS=$'\t' read -r user date email; do
    cmd -u "$user" -d "$date" -e "$email"
  done

参考文献

man 1 jq, version
stedolan/jq: Command-line JSON processor
Cookbook · stedolan/jq Wiki
json – How to check for presence of ‘key’ in jq before iterating over the values – Stack Overflow
json – jq – select an attribute beginning with a string – Unix & Linux Stack Exchange
How do I update a single value in a json document using jq? – Stack Overflow
json – How do I assign something to a JQ variable I’ve already set in JQ? – Stack Overflow