layui遍历json数组_shell脚本:json格式化与字段抓取(下)接上⼀篇。
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=$1
FILTER=$2
NEED_CHECK=$3
FORMATTED_JSON=
# 检查json是否合法
if [ "0" != "$NEED_CHECK" ]; then
FORMATTED_JSON=`format "$JSON" "$4"`
else
FORMATTED_JSON=$JSON
fi
# 读取上⼀条命令return的执⾏状态,⾮0表⽰异常
if [ $? != 0 ]; then
echo "Error [line:$LINENO]: invalid json"
return 1
fi
# .直接返回全部json
if [ "." = "$FILTER" ]; then
echo "$FORMATTED_JSON"
return 0
fi
# 将复合过滤条件以.号拆分成单个的过滤条件数组
# 所有的.号替换成空格,加上()即可⾃动变成数组
FILTER_ARRAY=(${FILTER//./ })
# 遍历所有单个的过滤条件
for(( i=0; i<${#FILTER_ARRAY[*]}; i++ ))
do
CURRENT_FILTER=${FILTER_ARRAY[$i]}
# []的情况
# 对数组的各个元素递归
if [  "[]" = "$CURRENT_FILTER" ]; then
# 检查json是否为数组
if [ "[" != "${FORMATTED_JSON:0:1}" ]; then
if [ "[" != "${FORMATTED_JSON:0:1}" ]; then
echo "Error [line:$LINENO]: not an array"
return 1
fi
CHILD_JSON_ARRAY=`getChildrenJson "$FORMATTED_JSON"`
# 后续的过滤条件
REMAINING_FILTER=
for(( j=`expr $i + 1`; j<${#FILTER_ARRAY[*]}; j++ ))
do
REMAINING_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"`
# 其它都当做读取字段处理
else
FORMATTED_JSON=`getFieldValue "$FORMATTED_JSON" "$CURRENT_FILTER"`        fi
done
echo "$FORMATTED_JSON"
return 0
}
# 函数:获取数组json的所有⼦json,或指定位置的⼦json
# ⼊参1:json,必须是数组
# ⼊参2:index,指定想要的⼦json的位置,从0开始,不指定则获取全部
# 出参:json数组
getChildrenJson() {
JSON=$1
INDEX=$2
RESULT_JSON_ARRAY=()
# []{}块,每关闭⼀个{}块,即为⼀个⼦json,根[块关闭之后则为扫描结束
BLOCK_ARRAY=('[')
CURRENT=
CHILD_JSON=
# 从1开始,因为第0位的[已经记录到BLOCK_ARRAY⾥⾯去了
JSON_LENGTH=${#JSON}
POSITION=1
while (( ${POSITION}<${JSON_LENGTH} ))
do
CURRENT=${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" ]; then
if [ """ = "$CURRENT" ]; then
unset BLOCK_ARRAY[$LAST_BLOCK_INDEX]
if [ ${#BLOCK_ARRAY[*]} == 1 ]; then
if [ ${#BLOCK_ARRAY[*]} == 1 ]; then
# 如果指定了index参数,并且此处恰好就是,则返回当前 child
if [ "${#RESULT_JSON_ARRAY[*]}" = "$INDEX" ]; then
echo "$CHILD_JSON"
return 0
fi
# child 添加到数组
RESULT_JSON_ARRAY[${#RESULT_JSON_ARRAY[*]}]="$CHILD_JSON"                    # 清空 child
CHILD_JSON=
# 如果下⼀个字符是逗号,跳过
NEXT_POSITION=`expr $POSITION + 1`
if [ "," = "${JSON:NEXT_POSITION:1}" ]; then
let POSITION++
fi
fi
fi
let POSITION++
continue
fi
if [ "{" = "$CURRENT" ]; then
# 记录⼀个{}块
BLOCK_ARRAY[${#BLOCK_ARRAY[*]}]='{'
elif [ "}" = "$CURRENT" ]; then
# 关闭⼀个{}块
unset BLOCK_ARRAY[`expr ${#BLOCK_ARRAY[*]} - 1`]
# 退出到了根[]块,表⽰⼀个child已经结束
if [ ${#BLOCK_ARRAY[*]} == 1 ]; then
# 如果指定了index参数,并且此处恰好就是,则返回当前 child
if [ "${#RESULT_JSON_ARRAY[*]}" = "$INDEX" ]; then
echo "$CHILD_JSON"
return 0
fi
# child 添加到数组
RESULT_JSON_ARRAY[${#RESULT_JSON_ARRAY[*]}]="$CHILD_JSON"                # 清空 child
CHILD_JSON=
# 如果下⼀个字符是逗号,跳过
NEXT_POSITION=`expr $POSITION + 1`
if [ "," = "${JSON:NEXT_POSITION:1}" ]; then
let POSITION++
fi
fi
elif [ """ = "$CURRENT" ]; then
BLOCK_ARRAY[${#BLOCK_ARRAY[*]}]="""
elif [ "," = "$CURRENT" ]; then
# 当前在根[]块,表⽰⼀个child已经结束
if [ ${#BLOCK_ARRAY[*]} == 1 ]; then
# 删除已经添加进去的逗号
CHILD_JSON="${CHILD_JSON%,}"
# 如果指定了index参数,并且此处恰好就是,则返回当前 child
if [ "${#RESULT_JSON_ARRAY[*]}" = "$INDEX" ]; then
echo "$CHILD_JSON"
return 0
fi
# child 添加到数组
RESULT_JSON_ARRAY[${#RESULT_JSON_ARRAY[*]}]="$CHILD_JSON"                # 清空 child
CHILD_JSON=
fi
fi
let POSITION++
done
# ⾛到这⾥说明没有传 index,或 index 越界
if [ "$INDEX" ]; then
echo "Error [line:$LINENO]: array out of bounds"
echo "Error [line:$LINENO]: array out of bounds"
exit 1
fi
echo "${RESULT_JSON_ARRAY[*]}"
return 0
}
# 函数:获取指定字段名称的值,默认json中同⼀层次不存在相同的字段名称
# ⼊参1:json
# ⼊参2:字段名称
# 出参:指定字段名称的值
getFieldValue() {
JSON=$1
FIELD=$2
VALUE=
POSITION=0
LENGTH=${#JSON}
FIELD_LENGTH=${#FIELD}
# 字段名称长度 + "": 的长度3个字符
MATCH_LENGTH=`expr $FIELD_LENGTH + 3`
while(( $POSITION<$LENGTH ))
do
MATCH_STR=${JSON:POSITION:MATCH_LENGTH}
# 匹配到了
if [ "$MATCH_STR" = ""$FIELD":" ]; then
POSITION=`expr $POSITION + $MATCH_LENGTH`
# 向后读取 value
BLOCK_ARRAY=()
CURRENT=${JSON:POSITION:1}
# 如果 value 的第⼀位不是{,[,"的任何⼀个,则直接开始读取,读到,或}结束            if [[ "{" != "$CURRENT" && "[" != "$CURRENT" && """ != "$CURRENT" ]]; then                VALUE="$CURRENT"
let POSITION++
while(( $POSITION<$LENGTH  ))
do
CURRENT=${JSON:POSITION:1}
if [[ "," = "$CURRENT" || "}" = "$CURRENT" ]]; then
echo "$VALUE"
return 0
else
VALUE="${VALUE}${CURRENT}"
fi
let POSITION++
done
echo "Error [line:$LINENO]: unknown error, maybe bug"
return 1
fi
# 读取第⼀个{,[,或",直到退出为⽌
BLOCK_ARRAY[0]="$CURRENT"
VALUE="$CURRENT"
let POSITION++
while(( ${#BLOCK_ARRAY[*]} != 0 ))
do
CURRENT=${JSON:POSITION:1}
VALUE="${VALUE}${CURRENT}"
if [[ "}" = "$CURRENT" || "]" = "$CURRENT" ]]; then
filter过滤对象数组unset BLOCK_ARRAY[`expr ${#BLOCK_ARRAY[*]} - 1`]
elif [[ "{" = "$CURRENT" || "[" = "$CURRENT" ]]; then
BLOCK_ARRAY[${#BLOCK_ARRAY[*]}]="$CURRENT"
elif [ """ = "$CURRENT" ]; then
LAST_BLOCK_INDEX=`expr ${#BLOCK_ARRAY[*]} - 1`
CURRENT_BLOCK=${BLOCK_ARRAY[$LAST_BLOCK_INDEX]}
if [ """ = "$CURRENT_BLOCK" ]; then
unset BLOCK_ARRAY[$LAST_BLOCK_INDEX]
else
BLOCK_ARRAY[${#BLOCK_ARRAY[*]}]="""
BLOCK_ARRAY[${#BLOCK_ARRAY[*]}]="""
fi
fi
let POSITION++
if [ $POSITION -ge $LENGTH ]; then
break
fi
done
echo "$VALUE"
return 0
fi
let POSITION++
done
echo "Error [line:$LINENO]: not found field $FIELD"
return 1
}
# 函数:去掉所有空⽩字符
# ⼊参1:字符串
# 出参:去掉所有空⽩字符的字符串
clearBlank() {
STR=$1
RESULT=
POSITION=0
LENGTH=${#STR}
while(( $POSITION<$LENGTH ))
do
CURRENT=${STR:POSITION:1}
if [ $CURRENT ]; then
RESULT="${RESULT}${CURRENT}"
fi
let POSITION++
done
echo "$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函数,提⽰命令使⽤⽅式:

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。