在linux中,解析json一般都会使用jq,jq固然好用,但是要额外安装就不太友好了。如果你在网上搜索通过shell来解析json的方法,你会发现都是些啥玩意儿。既然如此,那就动手撸一个吧。
有以下特性:
-
她能兼容jq的路径表达式
-
.name
-
.[0].name
-
.[0][0].name
-
...
-
纯shell,其实用的是awk。纯bash不好搞,就曲线救一下国呗
代码如下,拿去不谢。转载请标出处。转载请标出处。转载请标出处。
jsonq() {
json=$(cat)
awk -v json="$json" -v json_orgi="$json" -v key="$1" '
function strlastchar(s) {
return substr(s, length(s), 1)
function startwith(s, c) {
start = substr(s, 1, 1)
return start == c
function endwith(s, c) {
return strlastchar(s) == c
function innerstr(s) { # 取出括号/引号内的内容
return substr(s, 2, length(s)-2)
function strindex(s, n) { # 字符串通过下标取值,索引是从1开始的
return substr(s, n, 1)
function trim(s) {
sub("^[ \n]*", "", s);
sub("[ \n]*$", "", s);
return s
function findValueByKey(s, k) {
if ("\""k"\"" != substr(s, 1, length(k)+2)) {exit 0}
s = trim(s)
start = 0; stop = 0; layer = 0
for (i = 2 + length(k) + 1; i <= length(s); ++i) {
lastChar = substr(s, i - 1, 1)
currChar = substr(s, 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(s) || stop > length(s) || start >= stop) {
exit 0
} else {
return trim(substr(s, start, stop - start))
function unquote(s) {
if (startwith(s, "\"")) {
s = substr(s, 2, length(s)-1)
if (endwith(s, "\"")) {
s = substr(s, 1, length(s)-1)
return s
BEGIN{
if (match(key, /^\./) == 0) {exit 0;}
sub(/\][ ]*\[/,"].[", key)
split(key, ks, ".")
if (length(ks) == 1) {print json; exit 0}
for (j = 2; j <= length(ks); j++) {
k = ks[j]
if (startwith(k, "[") && endwith(k, "]") == 1) { # [n]
idx = innerstr(k)
currentIdx = -1
# 找匹配对
pairs = ""
json = trim(json)
if (startwith(json, "[") == 0) {
exit 0
start = 2
cursor = 2
for (; cursor <= length(json); cursor++) {
current = strindex(json, cursor)
if (current == " " || current == "\n") {continue} # 忽略空白
if (current == "[" || current == "{") {
if (length(pairs) == 0) {start = cursor}
pairs = pairs""current
if (current == "]" || current == "}") {
if ((strlastchar(pairs) == "[" && current == "]") || (strlastchar(pairs) == "{" && current == "}")) {
pairs = substr(pairs, 1, length(pairs)-1) # 删掉最后一个字符
if (pairs == "") { # 匹配到了所有的左括号
currentIdx++
if (currentIdx == idx) {
json = substr(json, start, cursor-start+1)
break
} else {
pairs = pairs""current
} else {
# 到这里,就只能是{"key": "value"}或{"key":{}}或{"key":[{}]}
pairs = ""
json = trim(json)
if (startwith(json, "[")) {exit 0}
#if (!startwith(json, "\"") || !startwith(json, "{")) {json="\""json}
# 找匹配的键
start = 2
cursor = 2
noMatch = 0
for (; cursor <= length(json); cursor++) {
current = strindex(json, cursor)
if (current == " " || current == "\n" || current == ",") {continue} # 忽略空白和逗号
if (substr(json, cursor, length(k)+2) == "\""k"\"") {
json = findValueByKey(substr(json, cursor, length(json)-cursor+1), k)
break
} else {
noMatch = 1
if (noMatch) {
pos = match(substr(json, cursor+1, length(json)-cursor), /[^(\\")]"/)
ck = substr(substr(json, cursor+1, length(json)-cursor), 1, pos)
t = findValueByKey(substr(json, cursor, length(json)-cursor+1), ck)
tLen = length(t)
sub(/\\/, "\\\\", t)
pos = match(substr(json, cursor+1, length(json)-cursor), t)
if (pos != 0) {
cursor = cursor + pos + tLen
noMatch = 0
continue
if (json_orgi == json) { print;exit 0 }
print unquote(json)
doublebackslash() {
echo "$1" | sed 's/\\/\\\\/g'
json='
"code": 200,
"msg": "success",
"data": {
"orderNo": "test_order_no"
json2='
"name": "haxi",
"age": 18
"name": "hh",
"age": 28
"name": "crz"
json3='{"name":"ha\"ha", "age":18}'
json4='
"message": "{\"code\": 200}"
json5='{"id":"15331352","message":"ok"}'
json6='{"result":"/\n","status":"Done"}'
echo "$json" | jsonq ".data"
echo "$json" | jsonq ".data.orderNo"
echo "$json" | jsonq ".code"
echo "$json2" | jsonq ".[0][1].name"
echo "$json2" | jsonq ".[1][0].name"
echo "$json2" | jsonq ".[1][0]"
echo "$json2" | jsonq ".[0][0]"
echo "$json3" | jsonq ".age"
echo "$json3" | jsonq ".name"
echo "$json4" | jsonq ".message"
echo "$json5" | jsonq ".message"
echo "$json6" | jsonq ".result"
echo "$json6" | jsonq ".status"
echo "$json6" | jsonq ".data"
标签: none
已有 4 条评论
fumj
: 牛
liucen
: 大佬,rocketmq5.0 的api 中consumer 默认...
陈日志
: 不会,只会校验新的commit。你可以试下各种场景,有问题再沟通。
devops_user
: 请教您一下。
在上文脚本中的用户校验逻辑,是建立在 “Push提...
陈日志
: 不能遍历,请用jq
sxs
: 请问如何遍历呀?有 demo 示例嘛?
sxs
: 请问如何遍历呀?有 demo 示例嘛?
ysicing
: mysql8.0跑问题也不大,测试过。
July 2024
May 2024
April 2024
March 2024
December 2023
February 2023
December 2022
November 2022
September 2022
July 2022
January 2022
December 2021
March 2021
February 2021
December 2020
November 2020
October 2020
August 2020
May 2020
April 2020
March 2020
February 2020
December 2019
October 2019
September 2019
August 2019
July 2019
March 2019
February 2019
January 2019
December 2018
June 2016
May 2016
文章 RSS
评论 RSS
Typecho