如何在bash中使用JQ遍历JSON数据并校验各字段取值
实现方案
错误原因
- 你使用的for循环默认会按任意空白字符(空格、换行、制表符)拆分输入,JSON内容中的空格、字段间隔会导致拆分出的结果不是完整的单个对象
- 未指定jq提取
.data数组的元素,直接输出完整JSON结构,无法按条目拆分
正确实现
方案1:通用场景(无特殊换行字符)
使用-c参数让jq将每个数组成员压缩为单行JSON,配合while read逐行读取,避免拆分混乱
# 假设JSON内容存储在变量$json中 while IFS= read -r item; do # 提取各字段存入变量 seen=$(jq -r '.seen' <<< "$item") id=$(jq -r '.id' <<< "$item") tinyId=$(jq -r '.tinyId' <<< "$item") status=$(jq -r '.status' <<< "$item") acknowledged=$(jq -r '.acknowledged' <<< "$item") isSeen=$(jq -r '.isSeen' <<< "$item") # 此处写入你自己的校验逻辑 echo "处理条目 $tinyId,状态:$status,是否已读:$isSeen" done < <(jq -c '.data[]' <<< "$json")
方案2:高性能方案(仅需字段值,不需要操作完整JSON对象)
一次性通过jq把所有字段按制表符拼接输出,单次读取所有变量,避免循环内反复调用jq
while IFS=$'\t' read -r seen id tinyId status acknowledged isSeen; do # 直接使用提取后的变量即可 echo "处理条目 $tinyId,状态:$status,是否已读:$isSeen" done < <(jq -r '.data[] | [.seen, .id, .tinyId, .status, .acknowledged, .isSeen] | join("\t")' <<< "$json")
方案3:极端兼容场景(字段包含换行、特殊字符)
通过base64编码转义特殊字符,完全避免拆分异常
while IFS= read -r item_b64; do item=$(base64 -d <<< "$item_b64") seen=$(jq -r '.seen' <<< "$item") id=$(jq -r '.id' <<< "$item") tinyId=$(jq -r '.tinyId' <<< "$item") status=$(jq -r '.status' <<< "$item") acknowledged=$(jq -r '.acknowledged' <<< "$item") isSeen=$(jq -r '.isSeen' <<< "$item") # 校验逻辑 done < <(jq -r '.data[] | @base64' <<< "$json")
注意事项
- 优先使用进程替换
< <(命令)的方式将jq输出传入while循环,避免管道写法jq ... | while ...触发子shell,导致循环内定义的变量外部无法访问 - jq的
-r参数会输出原始字符串,自动去掉JSON值的双引号,适合直接存入bash变量使用
内容的提问来源于stack exchange,提问作者Dave Shaw
相关产品推荐
相关产品推荐

