接上一篇

2 字段抓取

2.1 规则制定

先规定字段抓取的规则,对于给定的json

  • .:表示整个json
  • .fieldName:表示抓取fieldName字段的值,可能是字符串、布尔值、数字,或子json对象;
  • .[]:如果json或子json对象是数组,表示获取数组的所有元素;
  • .[0]:如果json或子json对象是数组,表示获取数组的第一个元素,其它.[1].[2]以此类推;
  • 以上可以复合使用,如.[].fieldName1.[0].fieldName2,需要最外层json是一个数组,表示获取最外层数组所有元素的fieldName1字段的数组的第一个元素的fieldName2字段值。

目前就考虑这些功能。

2.2 shell 实现

可以跟上一篇里面的shell代码放在一起。

# ------------------- function --------------------
# 函数:抓取(过滤)出json指定字段值
# 入参1:json
# 入参2:过滤条件,支持“.”,“.[]”,“.fieldName”,“.[index]”,及其组合
# 入参3:是否需要检查json合法性,0:不需要;其它:需要
# 入参4:缩进量,格式化时用到
fetch() {JSON=$1FILTER=$2NEED_CHECK=$3FORMATTED_JSON=# 检查json是否合法if [ "0" != "$NEED_CHECK" ]; thenFORMATTED_JSON=`format "$JSON" "$4"`elseFORMATTED_JSON=$JSONfi# 读取上一条命令return的执行状态,非0表示异常if [ $? != 0 ]; thenecho "Error [line:$LINENO]: invalid json"return 1fi# .直接返回全部jsonif [ "." = "$FILTER" ]; thenecho "$FORMATTED_JSON"return 0fi# 将复合过滤条件以.号拆分成单个的过滤条件数组# 所有的.号替换成空格,加上()即可自动变成数组FILTER_ARRAY=(${FILTER//./ })# 遍历所有单个的过滤条件for(( i=0; i<${#FILTER_ARRAY[*]}; i++ ))doCURRENT_FILTER=${FILTER_ARRAY[$i]}# []的情况# 对数组的各个元素递归if [  "[]" = "$CURRENT_FILTER" ]; then# 检查json是否为数组if [ "[" != "${FORMATTED_JSON:0:1}" ]; thenecho "Error [line:$LINENO]: not an array"return 1fiCHILD_JSON_ARRAY=`getChildrenJson "$FORMATTED_JSON"`# 后续的过滤条件REMAINING_FILTER=for(( j=`expr $i + 1`; j<${#FILTER_ARRAY[*]}; j++ ))doREMAINING_FILTER="${REMAINING_FILTER}.${FILTER_ARRAY[$j]}"done# 对每个 child 传入后续的过滤条件递归RESULT="["for CHILD in ${CHILD_JSON_ARRAY[*]}do# 递归调用RESULT="${RESULT}`fetch "$CHILD" "$REMAINING_FILTER" 0`,"done# 去掉最后一个“,”加上“]”# “%,*”表示从右侧开始,去掉最后一个“,”及右边的字符RESULT="${RESULT%,*}]"# 后续过滤条件已经做完,直接返回echo "$RESULT"return 0# [0],[1]...的情况# 似乎没有[0-9]+的写法,用[[0-9][0-9]*代替elif [ `echo "$CURRENT_FILTER" | grep "^[[0-9][0-9]*]$"` ]; then# 读取指定的数组元素# “#[”删除最左边的[INDEX=${CURRENT_FILTER#[}INDEX=${INDEX%]}FORMATTED_JSON=`getChildrenJson "$FORMATTED_JSON" "$INDEX"`# 其它都当做读取字段处理elseFORMATTED_JSON=`getFieldValue "$FORMATTED_JSON" "$CURRENT_FILTER"`fidoneecho "$FORMATTED_JSON"return 0
}# 函数:获取数组json的所有子json,或指定位置的子json
# 入参1:json,必须是数组
# 入参2:index,指定想要的子json的位置,从0开始,不指定则获取全部
# 出参:json数组
getChildrenJson() {JSON=$1INDEX=$2RESULT_JSON_ARRAY=()# []{}块,每关闭一个{}块,即为一个子json,根[块关闭之后则为扫描结束BLOCK_ARRAY=('[')CURRENT=CHILD_JSON=# 从1开始,因为第0位的[已经记录到BLOCK_ARRAY里面去了JSON_LENGTH=${#JSON}POSITION=1while (( ${POSITION}<${JSON_LENGTH} ))doCURRENT=${JSON:POSITION:1}CHILD_JSON="${CHILD_JSON}${CURRENT}"LAST_BLOCK_INDEX=`expr ${#BLOCK_ARRAY[*]} - 1`CURRENT_BLOCK=${BLOCK_ARRAY[$LAST_BLOCK_INDEX]}if [ """ = "$CURRENT_BLOCK" ]; thenif [ """ = "$CURRENT" ]; thenunset BLOCK_ARRAY[$LAST_BLOCK_INDEX]if [ ${#BLOCK_ARRAY[*]} == 1 ]; then# 如果指定了index参数,并且此处恰好就是,则返回当前 childif [ "${#RESULT_JSON_ARRAY[*]}" = "$INDEX" ]; thenecho "$CHILD_JSON"return 0fi# child 添加到数组RESULT_JSON_ARRAY[${#RESULT_JSON_ARRAY[*]}]="$CHILD_JSON"# 清空 childCHILD_JSON=# 如果下一个字符是逗号,跳过NEXT_POSITION=`expr $POSITION + 1`if [ "," = "${JSON:NEXT_POSITION:1}" ]; thenlet POSITION++fififilet POSITION++continuefiif [ "{" = "$CURRENT" ]; then# 记录一个{}块BLOCK_ARRAY[${#BLOCK_ARRAY[*]}]='{'elif [ "}" = "$CURRENT" ]; then# 关闭一个{}块unset BLOCK_ARRAY[`expr ${#BLOCK_ARRAY[*]} - 1`]# 退出到了根[]块,表示一个child已经结束if [ ${#BLOCK_ARRAY[*]} == 1 ]; then# 如果指定了index参数,并且此处恰好就是,则返回当前 childif [ "${#RESULT_JSON_ARRAY[*]}" = "$INDEX" ]; thenecho "$CHILD_JSON"return 0fi# child 添加到数组RESULT_JSON_ARRAY[${#RESULT_JSON_ARRAY[*]}]="$CHILD_JSON" # 清空 childCHILD_JSON=# 如果下一个字符是逗号,跳过NEXT_POSITION=`expr $POSITION + 1`if [ "," = "${JSON:NEXT_POSITION:1}" ]; thenlet POSITION++fi                fielif [ """ = "$CURRENT" ]; thenBLOCK_ARRAY[${#BLOCK_ARRAY[*]}]="""elif [ "," = "$CURRENT" ]; then# 当前在根[]块,表示一个child已经结束if [ ${#BLOCK_ARRAY[*]} == 1 ]; then# 删除已经添加进去的逗号CHILD_JSON="${CHILD_JSON%,}"# 如果指定了index参数,并且此处恰好就是,则返回当前 childif [ "${#RESULT_JSON_ARRAY[*]}" = "$INDEX" ]; thenecho "$CHILD_JSON"return 0fi# child 添加到数组RESULT_JSON_ARRAY[${#RESULT_JSON_ARRAY[*]}]="$CHILD_JSON"# 清空 childCHILD_JSON=fifilet POSITION++done# 走到这里说明没有传 index,或 index 越界if [ "$INDEX" ]; thenecho "Error [line:$LINENO]: array out of bounds"exit 1fiecho "${RESULT_JSON_ARRAY[*]}"return 0
}# 函数:获取指定字段名称的值,默认json中同一层次不存在相同的字段名称
# 入参1:json
# 入参2:字段名称
# 出参:指定字段名称的值
getFieldValue() {JSON=$1FIELD=$2VALUE=POSITION=0LENGTH=${#JSON}FIELD_LENGTH=${#FIELD}# 字段名称长度 + "": 的长度3个字符MATCH_LENGTH=`expr $FIELD_LENGTH + 3`while(( $POSITION<$LENGTH ))doMATCH_STR=${JSON:POSITION:MATCH_LENGTH}# 匹配到了if [ "$MATCH_STR" = ""$FIELD":" ]; thenPOSITION=`expr $POSITION + $MATCH_LENGTH`# 向后读取 valueBLOCK_ARRAY=()CURRENT=${JSON:POSITION:1}# 如果 value 的第一位不是{,[,"的任何一个,则直接开始读取,读到,或}结束if [[ "{" != "$CURRENT" && "[" != "$CURRENT" && """ != "$CURRENT" ]]; thenVALUE="$CURRENT"let POSITION++while(( $POSITION<$LENGTH  ))doCURRENT=${JSON:POSITION:1}if [[ "," = "$CURRENT" || "}" = "$CURRENT" ]]; thenecho "$VALUE"return 0elseVALUE="${VALUE}${CURRENT}"filet POSITION++doneecho "Error [line:$LINENO]: unknown error, maybe bug"return 1fi# 读取第一个{,[,或",直到退出为止BLOCK_ARRAY[0]="$CURRENT"VALUE="$CURRENT"let POSITION++while(( ${#BLOCK_ARRAY[*]} != 0 ))doCURRENT=${JSON:POSITION:1}VALUE="${VALUE}${CURRENT}"if [[ "}" = "$CURRENT" || "]" = "$CURRENT" ]]; thenunset BLOCK_ARRAY[`expr ${#BLOCK_ARRAY[*]} - 1`]elif [[ "{" = "$CURRENT" || "[" = "$CURRENT" ]]; thenBLOCK_ARRAY[${#BLOCK_ARRAY[*]}]="$CURRENT"elif [ """ = "$CURRENT" ]; thenLAST_BLOCK_INDEX=`expr ${#BLOCK_ARRAY[*]} - 1`CURRENT_BLOCK=${BLOCK_ARRAY[$LAST_BLOCK_INDEX]}if [ """ = "$CURRENT_BLOCK" ]; thenunset BLOCK_ARRAY[$LAST_BLOCK_INDEX]elseBLOCK_ARRAY[${#BLOCK_ARRAY[*]}]="""fifilet POSITION++if [ $POSITION -ge $LENGTH ]; thenbreakfidoneecho "$VALUE"return 0filet POSITION++doneecho "Error [line:$LINENO]: not found field $FIELD"return 1
}# 函数:去掉所有空白字符
# 入参1:字符串
# 出参:去掉所有空白字符的字符串
clearBlank() {STR=$1RESULT=POSITION=0LENGTH=${#STR}while(( $POSITION<$LENGTH ))doCURRENT=${STR:POSITION:1}if [ $CURRENT ]; thenRESULT="${RESULT}${CURRENT}"filet POSITION++doneecho "$RESULT"return 0
}

修改主流程:

# --------------------- main ----------------------
# 读取主流程参数
# 入参1:json
# 入参2:缩进字符数,默认为2
# 入参3:字段过滤器
echo -e `fatch "$1" "$3" "1" "$2"`
# --------------------- main ----------------------

现在,执行

pj '{"a":"b"}' 4 ".a"

即可返回a字段值b

3 设置命令参数

现在我们有三个参数了:json,缩进量,字段抓取的过滤器,有时候可能容易搞混掉传错顺序。

再添加一些命令行参数说明。

加一个help函数,提示命令使用方式:

# ------------------- function --------------------
# 函数:打印命令提示
help() {echo "$0 [-i INDENT] [-f FILTER] [-d JSON] [-c]Format json and fetch field value.
OPTIONS:-i      indent, 2 characters as default-f      filter, e.g. .fieldName1.[0].fieldName2.[].fieldName3-d      data, json-c      check if json is valid
" >&2exit 1
}
# ------------------- function --------------------

再修改主流程:

# --------------------- main ----------------------
# 入参
JSON=
INDENT=
FILTER=
CHECK=# 读取命令行参数
# 冒号表示该参数需要传值,如此处 -i -f -d 参数
while getopts "i:f:d:c" opt; do# 参数在 opt 变量里面case $opt ini)# 参数后的值存放在 OPTARG 变量中INDENT=$OPTARG;;f)FILTER=$OPTARG;;d)JSON=$OPTARG;;c)CHECK=1;;?)help;;esac
doneif [ ! "$JSON" ]; thenecho "Error: json missing"exit 1
fi
if [ ! "$INDENT" ]; thenINDENT=2
fi
if [ ! "$FILTER" ]; thenFILTER="."
fi# 对于确定 json 一定是正确的格式的情况下,检查就有点多余
# 只有传了 -c 参数,才检查json是否合法
if [ $CHECK ]; thenCHECK_RESULT=`format "$JSON"`if [ $? != 0 ]; thenecho "Error [line:$LINENO]: invalid json"exit 1fi
fi
# 清除所有空白字符,否则目前的逻辑可能会对字段抓取的准确性造成一定影响
JSON=`clearBlank "$JSON"`
# 抓取字段
MAIN_RESULT=`fetch "$JSON" "$FILTER" "0" "$INDENT"`
# 尝试格式化
FORMATTED_MAIN_RESULT=`format "$MAIN_RESULT" "$INDENT"`
# 如果抓取的字段已经不是 json,格式化会失败,则返回非格式化的字段
if [ $? == 0 ]; thenecho -e "$FORMATTED_MAIN_RESULT"
elseecho -e "$MAIN_RESULT"
fi
# --------------------- main ----------------------

现在,使用

pj -d '{"a":"b"}' -i 4 -f .a -c

pj -d '{"a":"b"}' -f .a

即可抓取到字段a的值。

当然,也可以使用更复杂的json尝试。

layui遍历json数组_shell脚本:json格式化与字段抓取(下)相关推荐

  1. html遍历json数组,JS遍历JSON数组及获取JSON数组长度操作示例【测试可用】

    本文实例讲述了JS遍历JSON数组及获取JSON数组长度操作.分享给大家供大家参考,具体如下: 遍历 JSON 数组: var questions = data.data.questionnaire. ...

  2. ajax解析json中的对象数组对象,在JQuery中检索json数组后获取json对象Ajax

    我使用JQuery AJAX检索某些数据(标题和说明).正如你可以看到我打通的结果,并出结果的JSON数组和循环div标签中在JQuery中检索json数组后获取json对象Ajax success ...

  3. JSON解析实战篇:JSON数组中含JSON数组

    少年最好的地方就是:嘴里说着要放弃,心里却都憋着一口气. 前言 关于JSON和本文中所用的Fastjson介绍,可以查看我的这两篇博客: JSON简介:什么是JSON -> https://bl ...

  4. JS/Jquery遍历JSON对象、JSON数组、JSON数组字符串、JSON对象字符串

    JS遍历JSON对象 JSON对象 var jsonObj = {"id": 102,"year": "2019-2020","l ...

  5. html如何遍历ajax数组,ajax返回json数组遍历添加到html

    大致需求为类型限制根据类型获取不同结果列表,再根据模糊查询搜索出结果,效果如下:- 例子:利用AJAX返回JSON数据,间接访问数据库,查出Nation 表,并用下拉列表显示 造一个外部下拉列表框 J ...

  6. php json数组大小,php json转换成数组形式

    写的j的候通现端数是制这.效合应近环大过这业据son转换成数组的一个类和方法,实际上写的方法可以把大部分包含json字符串的数据结构转换成数组,在重说道.础过学开概码数项遍间里哦行览屏屏定处..容标中 ...

  7. presto 提取json数组中的json对象

    使用json_array_get函数,可以提取json数组中的指定位置,默认第一位的索引是0 json_array_get(json对象, 0)

  8. php怎么取json数组元素个数,json,数组_取出json数据中的某一项组成一个数组?,json,数组,php - phpStudy...

    取出json数据中的某一项组成一个数组? "jobs": [ { "name": "iOS开发工程师", "salary" ...

  9. Selenium实战脚本集(3)--抓取infoq里的测试新闻

    描述 打开infoq页面,抓取最新的一些测试文章 需要抓取文章的标题和内容 如果你有个人blog的话,可以将这些文章转载到自己的blog 要求 不要在新窗口打开文章 自行了解最新的测试思潮与实践

最新文章

  1. LeetCode简单题之猜数字大小
  2. 极大似然估计(Maximum Likelihood Estimattion Theory)是什么?极大似然估计的本质思想是什么?为什么极大似然可以作为损失函数使用?负对数似然损失函数(Negative
  3. 圣诞夜,让你的代码都变成圣诞树吧!
  4. Centos5, 6下更改系统时间和时区
  5. 电脑罗盘时钟代码_苹果电脑怎么设置数字时钟屏保 Word Clock for Mac安装教程
  6. 并查集 - 除法求值
  7. 杭电1262--寻找素数对(打表)
  8. hibernate cascade的真正含义
  9. 在html表格中怎么创建下拉列表,在html网页中如何做个下拉列表?下拉列表的方法有哪几种?...
  10. 23-windows下filebeat与logstash与elasticSearch的合并使用
  11. data自定义属性获取方法和设置
  12. MyEclipse的代码提示功能
  13. [题解] 2038: [2009国家集训队]小Z的袜子(hose)
  14. hdu 3501(欧拉函数)
  15. 微信小程序API-定位(位置)
  16. 初中地理老师教师资格证考试成功通过前辈备考经验分享
  17. Matlab/Simulink中信号线拉成斜线的方法
  18. IRT模型估计-EM算法
  19. Nginx配置ssl证书详细步骤
  20. hdu2955(变形的01背包)

热门文章

  1. [原创]SpotLight性能监控工具使用介绍
  2. 试题集 - 算法与编程
  3. LeetCode 86. 分隔链表 中等难度
  4. 华为OJ系列之---表示数字
  5. 强大的德国教育如何锻造孩子的健全人格
  6. matlab计算运行时间方法
  7. Linux系统及编程期末试题,《LINUX系统及其编程》考试试题及答案.doc
  8. unity桌面设置vnc_Ubuntu 16.04下安装VNC和Unity桌面系统
  9. oracle单表数据量上亿_MySQL数据库中,数据量越来越大,有什么具体的优化方案么?...
  10. 031_MessageBox弹框