如何使用jq更新JSON字段?Bootstrap脚本状态记录问题
问题与修复方案
需求说明
我需要实现一个bootstrap脚本,每次运行后将退出状态记录到JSON文件中,要求:
- 首次运行(文件不存在):创建JSON文件并添加布尔类型的
node_bootstrap_status字段 - 后续运行(文件已存在):仅更新
node_bootstrap_status的布尔值,保留文件中已有的其他字段
原脚本问题
原脚本在首次运行时正常工作,但后续运行会清空JSON文件的所有内容,原脚本代码如下:
exit_code=1 node_info_file="/etc/node_info.json" if [[ -f $node_info_file ]]; then # /etc/node_info.json exists echo "${node_info_file} exists" if [ $exit_code = 0 ]; then cat $node_info_file | jq --argjson node_bootstrap_status true '{"node_bootstrap_status": $node_bootstrap_status}' > $node_info_file else cat $node_info_file | jq --argjson node_bootstrap_status false '{"node_bootstrap_status": $node_bootstrap_status}' > $node_info_file fi else # /etc/node_info.json does NOT exists echo "${node_info_file} does not exist" touch ${node_info_file} if [ $exit_code = 0 ]; then echo '{}' | jq --argjson node_bootstrap_status true '{"node_bootstrap_status": $node_bootstrap_status}' > $node_info_file else echo '{}' | jq --argjson node_bootstrap_status false '{"node_bootstrap_status": $node_bootstrap_status}' > $node_info_file fi fi
问题根源
- 字段覆盖而非更新:jq命令
'{"node_bootstrap_status": $node_bootstrap_status}'直接生成仅包含目标字段的新JSON对象,完全丢弃了原文件中的其他字段。 - 文件读写竞态:
cat $node_info_file | jq ... > $node_info_file的写法存在问题,shell会先打开目标文件进行写入(清空内容),再执行cat读取文件,此时文件已经是空的,导致jq处理的是空数据。
修复后的脚本
exit_code=1 node_info_file="/etc/node_info.json" # 将退出码转换为布尔值 bootstrap_status=$([ $exit_code -eq 0 ] && echo "true" || echo "false") if [[ -f "$node_info_file" ]]; then echo "${node_info_file} exists, updating node_bootstrap_status" # 使用临时文件避免读写竞态,仅更新指定字段并保留其他内容 jq --argjson status "$bootstrap_status" '.node_bootstrap_status = $status' "$node_info_file" > "$node_info_file.tmp" && mv "$node_info_file.tmp" "$node_info_file" else echo "${node_info_file} does not exist, creating new file" # 创建包含目标字段的新JSON文件 jq --argjson status "$bootstrap_status" '{node_bootstrap_status: $status}' > "$node_info_file" fi
关键改进
- 使用jq的
.node_bootstrap_status = $status语法,仅更新指定字段,保留原JSON中的其他内容。 - 引入临时文件处理写入操作,避免直接覆盖原文件导致的读写竞态问题,同时防止脚本中断时损坏原文件。
- 简化逻辑,将退出码转布尔值的操作统一提取,减少重复代码。
验证结果
运行脚本后,JSON文件会保留原有字段并更新目标状态,示例结果:
{ "node_bootstrap_status": false, "foo": "bar" }
内容的提问来源于stack exchange,提问作者Korba
相关产品推荐
相关产品推荐

