Bash中如何修改YAML值且不破坏原有格式、注释与空白?
Bash环境无额外依赖修改YAML指定字段(保留原格式/注释/空白)
需求说明
需要完成YAML内容的精准修改,仅替换foo_bar节点下的version值,其余内容(注释、缩进、空行、其他字段)完全保持原样:
- 原始内容:
foo_bar: name: foo-bar version: "1.0.0-beta.1" abc_123: name: abc-123 version: "1.0.0-beta.1"
- 目标内容:
foo_bar: name: foo-bar version: "1.0.0-beta.2" abc_123: name: abc-123 version: "1.0.0-beta.1"
现有方案的缺陷:
- 用
yq修改会清空文件所有注释、自动调整空白排版,不符合要求 - JS正则替换逻辑可行,但运行环境不允许安装Node.js这类重依赖
实现方案
直接使用Linux环境默认预装的GNU sed即可实现,无任何额外依赖,不会改动目标字段外的任何内容。
方案1:块范围匹配(适配性更好)
通过地址范围精准锁定foo_bar节点的内容区间,仅在区间内替换目标version值,哪怕name和version字段之间插了其他配置、注释也能正常匹配:
# 直接原地修改,执行前自动生成.bak后缀的备份文件 sed -i.bak '/^foo_bar:/,/^[a-zA-Z0-9_]*:/{/version:/s/"1.0.0-beta.1"/"1.0.0-beta.2"/}' values.yaml
命令逻辑说明:
/^foo_bar:/,/^[a-zA-Z0-9_]*:/:匹配从foo_bar:顶级键开始,到下一个顶级键之前的所有内容,也就是foo_bar节点的完整范围- 范围内仅匹配带
version:的行执行替换,不会碰其他行内容 -i.bak:原地修改文件,同时自动生成values.yaml.bak备份,确认修改无误后可删除备份文件
方案2:完全对齐JS正则逻辑
如果需要和之前写的JS正则匹配逻辑完全相同(匹配name: foo-bar行后紧跟的version行),可以用sed的整文件读取模式,替换效果和JS代码100%一致:
sed -i.bak -z 's/\(name:\s*foo-bar\n\s*version:\s*"\)[^"]*"/\11.0.0-beta.2"/' values.yaml
命令逻辑说明:
-z参数让sed把整个文件作为单个字符串处理,跨行正则匹配逻辑和JS完全一致- 正则规则和原有JS代码完全等价,只会命中
foo_bar下name字段之后紧跟的version值
注意事项
- 以上命令基于GNU sed,所有主流Linux发行版(Debian/Ubuntu/CentOS/RHEL等)默认预装,不需要额外安装
- macOS系统自带的是BSD sed,可通过包管理器安装gnu-sed后用
gsed替换上述命令中的sed即可 - 两种方案都不会改动非目标位置的任何内容,原有注释、缩进、空行、排版会完整保留,解决了yq重排格式、丢失注释的问题
内容的提问来源于stack exchange,提问作者Forivin
相关产品推荐
相关产品推荐

