Bash使用awk/sed编辑YAML向monitor列表末尾追加条目的求助
问题根因
你的脚本出错的核心原因有两个:
- 原有
getline函数返回的是monitor:所在的行号,sed的a命令是在指定行后插入内容,所以自然会插在monitor列表所有已有条目的最前面 - 你在循环里每次插入前都重新查询行号,插入操作会改变文件的行号,多次插入会出现位置偏移
推荐解决方案(优先用YAML专用工具)
处理结构化的YAML文件最稳妥的方案是用专门的YAML处理工具yq,不需要关心行号、缩进等格式细节,直接操作YAML结构,不会出现格式错乱问题:
# 适配mikefarah/yq v4版本 yq eval ' (.[] | select(has("monitor")).monitor) += [{"name": "orch_vm1"}, {"name": "orch_vm2"}] ' -i impulse.yaml
纯sed/awk适配方案(如果环境不能安装yq)
如果只能用基础shell工具,可以修改行号查询逻辑,找到monitor块的最后一行位置,单次查询后倒序插入避免行号偏移:
修改后的完整脚本
get_monitor_end_line() { awk ' BEGIN { find_monitor = 0 end_line = 0 } # 标记进入monitor块 /^- monitor:/ { find_monitor = 1 } # 碰到下一个顶级列表项,说明monitor块结束,前一行就是插入位置 find_monitor == 1 && /^- / && !/^- monitor:/ { end_line = NR - 1 exit } # 持续更新monitor块的最后一行行号 find_monitor == 1 { end_line = NR } END { print end_line } ' "$1" } filename="impulse.yaml" # 先查询一次插入位置,避免多次查询受插入操作影响 insert_line=$(get_monitor_end_line "$filename") # 倒序插入,保证最终顺序符合预期 for vm_name in orch_vm2 orch_vm1; do sed -i "${insert_line}a\ - name: ${vm_name}" "$filename" done
注意事项
该方案依赖你当前YAML的固定格式:顶级配置都是- 开头的列表项,monitor下的子项缩进为4空格,如果后续YAML格式有调整,需要同步修改匹配规则。
内容的提问来源于stack exchange,提问作者Vijay_bhaskar_K
相关产品推荐
相关产品推荐

