在linux中,解析json一般都会使用jq,jq固然好用,但是要额外安装就不太友好了。如果你在网上搜索通过shell来解析json的方法,你会发现都是些啥玩意儿。既然如此,那就动手撸一个吧。

有以下特性:

  • 她能兼容jq的路径表达式

    • .name
    • .[0].name
    • .[0][0].name
    • ...
  • 纯shell,其实用的是awk。纯bash不好搞,就曲线救一下国呗

代码如下,拿去不谢。转载请标出处。转载请标出处。转载请标出处。

  1. jsonq() {
  2. json=$(cat)
  3. awk -v json="$json" -v json_orgi="$json" -v key="$1" '
  4. function strlastchar(s) {
  5. return substr(s, length(s), 1)
  6. }
  7. function startwith(s, c) {
  8. start = substr(s, 1, 1)
  9. return start == c
  10. }
  11. function endwith(s, c) {
  12. return strlastchar(s) == c
  13. }
  14. function innerstr(s) { # 取出括号/引号内的内容
  15. return substr(s, 2, length(s)-2)
  16. }
  17. function strindex(s, n) { # 字符串通过下标取值,索引是从1开始的
  18. return substr(s, n, 1)
  19. }
  20. function trim(s) {
  21. sub("^[ \n]*", "", s);
  22. sub("[ \n]*$", "", s);
  23. return s
  24. }
  25. function findValueByKey(s, k) {
  26. if ("\""k"\"" != substr(s, 1, length(k)+2)) {exit 0}
  27. s = trim(s)
  28. start = 0; stop = 0; layer = 0
  29. for (i = 2 + length(k) + 1; i <= length(s); ++i) {
  30. lastChar = substr(s, i - 1, 1)
  31. currChar = substr(s, i, 1)
  32. if (start <= 0) {
  33. if (lastChar == ":") {
  34. start = currChar == " " ? i + 1: i
  35. if (currChar == "{" || currChar == "[") {
  36. layer = 1
  37. }
  38. }
  39. } else {
  40. if (currChar == "{" || currChar == "[") {
  41. ++layer
  42. }
  43. if (currChar == "}" || currChar == "]") {
  44. --layer
  45. }
  46. if ((currChar == "," || currChar == "}" || currChar == "]") && layer <= 0) {
  47. stop = currChar == "," ? i : i + 1 + layer
  48. break
  49. }
  50. }
  51. }
  52. if (start <= 0 || stop <= 0 || start > length(s) || stop > length(s) || start >= stop) {
  53. exit 0
  54. } else {
  55. return trim(substr(s, start, stop - start))
  56. }
  57. }
  58. function unquote(s) {
  59. if (startwith(s, "\"")) {
  60. s = substr(s, 2, length(s)-1)
  61. }
  62. if (endwith(s, "\"")) {
  63. s = substr(s, 1, length(s)-1)
  64. }
  65. return s
  66. }
  67. BEGIN{
  68. if (match(key, /^\./) == 0) {exit 0;}
  69. sub(/\][ ]*\[/,"].[", key)
  70. split(key, ks, ".")
  71. if (length(ks) == 1) {print json; exit 0}
  72. for (j = 2; j <= length(ks); j++) {
  73. k = ks[j]
  74. if (startwith(k, "[") && endwith(k, "]") == 1) { # [n]
  75. idx = innerstr(k)
  76. currentIdx = -1
  77. # 找匹配对
  78. pairs = ""
  79. json = trim(json)
  80. if (startwith(json, "[") == 0) {
  81. exit 0
  82. }
  83. start = 2
  84. cursor = 2
  85. for (; cursor <= length(json); cursor++) {
  86. current = strindex(json, cursor)
  87. if (current == " " || current == "\n") {continue} # 忽略空白
  88. if (current == "[" || current == "{") {
  89. if (length(pairs) == 0) {start = cursor}
  90. pairs = pairs""current
  91. }
  92. if (current == "]" || current == "}") {
  93. if ((strlastchar(pairs) == "[" && current == "]") || (strlastchar(pairs) == "{" && current == "}")) {
  94. pairs = substr(pairs, 1, length(pairs)-1) # 删掉最后一个字符
  95. if (pairs == "") { # 匹配到了所有的左括号
  96. currentIdx++
  97. if (currentIdx == idx) {
  98. json = substr(json, start, cursor-start+1)
  99. break
  100. }
  101. }
  102. } else {
  103. pairs = pairs""current
  104. }
  105. }
  106. }
  107. } else {
  108. # 到这里,就只能是{"key": "value"}或{"key":{}}或{"key":[{}]}
  109. pairs = ""
  110. json = trim(json)
  111. if (startwith(json, "[")) {exit 0}
  112. #if (!startwith(json, "\"") || !startwith(json, "{")) {json="\""json}
  113. # 找匹配的键
  114. start = 2
  115. cursor = 2
  116. noMatch = 0
  117. for (; cursor <= length(json); cursor++) {
  118. current = strindex(json, cursor)
  119. if (current == " " || current == "\n" || current == ",") {continue} # 忽略空白和逗号
  120. if (substr(json, cursor, length(k)+2) == "\""k"\"") {
  121. json = findValueByKey(substr(json, cursor, length(json)-cursor+1), k)
  122. break
  123. } else {
  124. noMatch = 1
  125. }
  126. if (noMatch) {
  127. pos = match(substr(json, cursor+1, length(json)-cursor), /[^(\\")]"/)
  128. ck = substr(substr(json, cursor+1, length(json)-cursor), 1, pos)
  129. t = findValueByKey(substr(json, cursor, length(json)-cursor+1), ck)
  130. tLen = length(t)
  131. sub(/\\/, "\\\\", t)
  132. pos = match(substr(json, cursor+1, length(json)-cursor), t)
  133. if (pos != 0) {
  134. cursor = cursor + pos + tLen
  135. }
  136. noMatch = 0
  137. continue
  138. }
  139. }
  140. }
  141. }
  142. if (json_orgi == json) { print;exit 0 }
  143. print unquote(json)
  144. }'
  145. }
  146. doublebackslash() {
  147. echo "$1" | sed 's/\\/\\\\/g'
  148. }
  149. json='
  150. {
  151. "code": 200,
  152. "msg": "success",
  153. "data": {
  154. "orderNo": "test_order_no"
  155. }
  156. }
  157. '
  158. json2='
  159. [
  160. [{
  161. "name": "haxi",
  162. "age": 18
  163. },
  164. {
  165. "name": "hh",
  166. "age": 28
  167. }
  168. ],
  169. [{
  170. "name": "crz"
  171. }]
  172. ]
  173. '
  174. json3='{"name":"ha\"ha", "age":18}'
  175. json4='
  176. {
  177. "message": "{\"code\": 200}"
  178. }
  179. '
  180. json5='{"id":"15331352","message":"ok"}'
  181. json6='{"result":"/\n","status":"Done"}'
  182. echo "$json" | jsonq ".data"
  183. echo "$json" | jsonq ".data.orderNo"
  184. echo "$json" | jsonq ".code"
  185. echo "$json2" | jsonq ".[0][1].name"
  186. echo "$json2" | jsonq ".[1][0].name"
  187. echo "$json2" | jsonq ".[1][0]"
  188. echo "$json2" | jsonq ".[0][0]"
  189. echo "$json3" | jsonq ".age"
  190. echo "$json3" | jsonq ".name"
  191. echo "$json4" | jsonq ".message"
  192. echo "$json5" | jsonq ".message"
  193. echo "$json6" | jsonq ".result"
  194. echo "$json6" | jsonq ".status"
  195. echo "$json6" | jsonq ".data"

标签: none

已有 5 条评论

  1. 佩玉鸣鸾 佩玉鸣鸾

    大佬牛逼,佩服佩服

  2. sxs sxs

    请问如何遍历呀?有 demo 示例嘛?

  3. sxs sxs

    请问如何遍历呀?有 demo 示例嘛?

  4. yqs yqs

    话说响应里面有中文似乎就会失效?这个有办法处理嘛

添加新评论