BASH脚本迭代替换JSON节点name值失败求助
嘿,刚接触bash、jq和JSON两周就啃这个任务,确实有点挠头——我完全懂你现在的挫败感,咱们一步步把这个问题捋顺、解决掉!
问题根源先搞清楚
你之前的脚本之所以只最后一个节点生效,核心原因是每次循环都从原始的demolabconfig.json读取内容:比如第一次循环改了第一个节点,写入文件;但第二次循环又重新读原始文件,相当于把第一次的修改覆盖了,从头改第二个节点……最后自然只有最后一次的修改能保留。如果循环次数超过了nodes的数量,还会出现null的情况(因为jq会给不存在的节点赋值)。
高效解决方法:让jq一次性处理所有替换
最好的思路是把所有主机名传给jq,让它一次性完成所有节点的替换,避免循环读写文件导致的覆盖问题。下面是具体的脚本和解释:
完整修复脚本
# 先把newhostnames.txt里的主机名逐行存入数组,避免空格等特殊字符干扰 mapfile -t hostnames < newhostnames.txt # 用jq一次性完成所有nodes的name替换,输出到新文件(避免直接覆盖原始文件) jq --argjson hostnames "$(printf '%s\n' "${hostnames[@]}" | jq -R . | jq -s .)" ' .lab.racks[] |= ( .nodes |= ( range(0; length) as $i | .[$i].name = ($hostnames[$i] // .[$i].name) ) ) ' demolabconfig.json > updated_demolabconfig.json
脚本细节解释
mapfile读取主机名:把newhostnames.txt的每一行存入hostnames数组,完美处理带空格的主机名(比如Tom-cat、Lucky-worm)。- 转成JSON数组传给jq:用
printf配合jq把bash数组转成jq能识别的JSON数组,存在$hostnames变量里。 - jq核心替换逻辑:
- 遍历每个
rack下的nodes列表 - 用索引
$i对应$hostnames数组的第$i个元素,替换name值 //是jq的空值合并运算符:如果主机名数量比nodes少,对应节点会保留原来的name,不会变成null
- 遍历每个
- 输出到新文件:直接输出到
updated_demolabconfig.json,调试时不会破坏原始文件,确认没问题后再替换原文件即可。
额外注意事项
- 确保
newhostnames.txt里的主机名数量和JSON中所有nodes的总数量匹配:如果主机名多了,多出来的会被忽略;如果少了,剩余节点保留原name(就是脚本里//的作用)。 - 如果你想直接覆盖原始文件,可以用
sponge工具(需要先安装moreutils包),避免临时文件的麻烦:...(前面的代码不变) )' demolabconfig.json | sponge demolabconfig.json
内容的提问来源于stack exchange,提问作者Akshatha Nadig




