Shell解析Json

本文遵循BY-SA版权协议,转载请附上原文出处链接。


本文作者: 黑伴白

本文链接: http://heibanbai.com.cn/posts/6fa0842e/

Shell解析Json

awk解析

  1. 先查找一个字符串:带双引号的key。如果没找到,则直接返回defaultValue
  2. 查找最近的冒号,找到后认为值的部分开始了,直到在层数上等于0时找到这3个字符:,}]
  3. 如果有多个同名key,则依次全部打印(不论层级,只按出现顺序)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# params: json, key, defaultValue
function getJsonValuesByAwk() {
awk -v json="$1" -v key="$2" -v defaultValue="$3" 'BEGIN{
foundKeyCount = 0
while (length(json) > 0) {
# pos = index(json, "\""key"\""); ## 这行更快一些,但是如果有value是字符串,且刚好与要查找的key相同,会被误认为是key而导致值获取错误
pos = match(json, "\""key"\"[ \\t]*?:[ \\t]*");
if (pos == 0) {if (foundKeyCount == 0) {print defaultValue;} exit 0;}

++foundKeyCount;
start = 0; stop = 0; layer = 0;
for (i = pos + length(key) + 1; i <= length(json); ++i) {
lastChar = substr(json, i - 1, 1)
currChar = substr(json, i, 1)

if (start <= 0) {
if (lastChar == ":") {
start = currChar == " " ? i + 1: i;
if (currChar == "{" || currChar == "[") {
layer = 1;
}
}
} else {
if (currChar == "{" || currChar == "[") {
++layer;
}
if (currChar == "}" || currChar == "]") {
--layer;
}
if ((currChar == "," || currChar == "}" || currChar == "]") && layer <= 0) {
stop = currChar == "," ? i : i + 1 + layer;
break;
}
}
}

if (start <= 0 || stop <= 0 || start > length(json) || stop > length(json) || start >= stop) {
if (foundKeyCount == 0) {print defaultValue;} exit 0;
} else {
print substr(json, start, stop - start);
}

json = substr(json, stop + 1, length(json) - stop)
}
}'
}

# 测试
json='{"code":200,"msg":"success","data":{"orderNo":"test_order_no"}}'
getJsonValuesByAwk "$json" "code" "defaultValue"
getJsonValuesByAwk "$json" "data" "defaultValue"
getJsonValuesByAwk "$json" "orderNo" "defaultValue"

# 结果
200
{"orderNo":"test_order_no"}
"test_order_no"

Json解析库: jq

jq是 stedolan 开发的一个轻量级的和灵活的命令行 JSON 处理器。

它主要用于在命令行界面处理 JSON 输入,并使用给定的过滤条件来过滤符合条件的新的 JSON 串。

通常在类 Unix 环境下,我们可以快速的使用 jq 来进行 JSON 数据格式化过滤和处理。

同时需要注意的是,该命令行工具和 awk/sed/grep 工具一样,属于系统的默认命令,如果系统没有该命令,可以尝试使用如下方式进行安装。

1
2
3
4
# Ubuntu 系列
$ sudo apt-get install jq
# CentOS 系列
$ yum install jq

基本用法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
jq [options] <jq filter> [file...]
jq [options] --args <jq filter> [strings...]
jq [options] --jsonargs <jq filter> [JSON_TEXTS...]

# options 可选参数列表和说明
-c 将格式化json输出为紧凑的字符串格式;
-n 使用`null`作为单个输入值;
-e 根据输出设置退出状态代码;
-s 将所有输入读取(吸取)到数组中;应用过滤器;
-r 输出原始字符串,而不是JSON文本;
-R 读取原始字符串,而不是JSON文本;
-C 为JSON输出填充颜色;
-M 单色(不要为JSON着色);
-S 在输出上排序对象的键;
--tab 使用制表符进行缩进;
--arg a v 将变量$a设置为value<v>;
--argjson a v 将变量$a设置为JSON value<v>;
--slurpfile a f 将变量$a设置为从<f>读取的JSON文本数组;
--rawfile a f 将变量$a设置为包含<f>内容的字符串;
--args 其余参数是字符串参数,而不是文件;
--jsonargs 其余的参数是JSON参数,而不是文件;
-- 终止参数处理;

基础使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
## 使用 . 参数默认格式化整个json数据
$ echo '{"Name":"CloudNativeOps","Owner":"GoOps","WebSite":"https://bgbiao.top/"}' | jq .
{
"Name": "CloudNativeOps",
"Owner": "GoOps",
"WebSite": "https://bgbiao.top/"
}

## 使用.$name 来获取指定filed
$ echo '{"Name":"CloudNativeOps","Owner":"GoOps","WebSite":"https://bgbiao.top/"}' | jq .Name
"CloudNativeOps"

## 解析json 中的层级数据
$ echo '{"Name":"CloudNativeOps","Owner":"GoOps","WebSite":"https://bgbiao.top/", "Contact": {"Email":"weichuangxxb@qq.com","QQ":"371990778","WeChat":"GoOps"} ,"Skills": [ {"name":"Python","type":"dev" }, {"name":"Golang","type":"dev" },{"name":"Ansible","type":"ops" },{"name":"Kubernetes","type":"dev" },{"name":"ElasticSearch","type":"ops" }]}' | jq .Contact
{
"Email": "weichuangxxb@qq.com",
"QQ": "371990778",
"WeChat": "GoOps"
}
### 仅输出 Contact 中的 WeChat
$ echo '{"Name":"CloudNativeOps","Owner":"GoOps","WebSite":"https://bgbiao.top/", "Contact": {"Email":"weichuangxxb@qq.com","QQ":"371990778","WeChat":"GoOps"} ,"Skills": [ {"name":"Python","type":"dev" }, {"name":"Golang","type":"dev" },{"name":"Ansible","type":"ops" },{"name":"Kubernetes","type":"dev" },{"name":"ElasticSearch","type":"ops" }]}' | jq .Contact.WeChat
"GoOps"

## 获取多个字段 (使用'.filed1,.filed2' 可以获取两个字段)
$ echo '{"Name":"CloudNativeOps","Owner":"GoOps","WebSite":"https://bgbiao.top/", "Contact": {"Email":"weichuangxxb@qq.com","QQ":"371990778","WeChat":"GoOps"} ,"Skills": [ {"name":"Python","type":"dev" }, {"name":"Golang","type":"dev" },{"name":"Ansible","type":"ops" },{"name":"Kubernetes","type":"dev" },{"name":"ElasticSearch","type":"ops" }]}' | jq ".Name,.Owner"
"CloudNativeOps"
"GoOps"

调用python

  • Python 2
1
2
export PYTHONIOENCODING=utf8
echo '{"Name":"CloudNativeOps","Owner":"GoOps","WebSite":"https://bgbiao.top/"}'|python -c "import sys, json; print json.load(sys.stdin)['WebSite']"
  • Python 3
1
echo '{"Name":"CloudNativeOps","Owner":"GoOps","WebSite":"https://bgbiao.top/"}'|python3 -c "import sys, json; print(json.load(sys.stdin)['WebSite']"

蚂蚁再小也是肉🥩!


Shell解析Json
http://heibanbai.com.cn/posts/6fa0842e/
作者
黑伴白
发布于
2022年3月9日
许可协议

“您的支持,我的动力!觉得不错的话,给点打赏吧 ୧(๑•̀⌄•́๑)૭”

微信二维码

微信支付

支付宝二维码

支付宝支付