如何用yq合并多个YAML文件并保留所有重复键值?
用yq合并YAML时合并重复键值(数组/逗号分隔字符串形式)
问题场景
现有三个YAML文件内容如下:
- file1.yaml
A: a: a1: value1 b: value2 B: b: value3
- file2.yaml
A: a: a1: value2
- file3.yaml
A: a: a1: value3
执行命令 yq ea '. as $item ireduce({}; . * $item)' file*.yaml 合并时,重复键A.a.a1仅保留最后一个值value3。需要将重复键的值合并为数组形式或逗号分隔的字符串,对应两种期望输出:
期望输出1(逗号分隔字符串)
A: a: a1: value1,value2,value3 b: value2 B: b: value3
期望输出2(数组形式)
A: a: a1: - value1 - value2 - value3 b: value2 B: b: value3
注:实际文件数量更多、结构更复杂,但值多为字符串,需支持值追加或新建键。
解决方案
方案1:合并为数组形式(对应期望输出2)
使用以下yq命令:
yq ea ' . as $item ireduce({}; reduce ($item | path(..)) as $path (.; if ($item | getpath($path)) | type == "string" then if getpath($path) | type == "string" then setpath($path; [getpath($path), $item | getpath($path)]) elif getpath($path) | type == "array" then setpath($path; getpath($path) + [$item | getpath($path)]) else setpath($path; [$item | getpath($path)]) end else . * $item end ) )' file*.yaml
如果需要去重,可在数组操作后添加| unique,比如[getpath($path), $item | getpath($path)] | unique。
逻辑说明:
- 遍历每个文件的所有键路径
- 针对字符串类型的值:
- 目标路径无值:直接转为数组
- 目标路径已有字符串:转为数组并加入新值
- 目标路径已有数组:追加新值到数组
- 非字符串类型的键值,保持
*运算符的常规合并逻辑
方案2:合并为逗号分隔字符串(对应期望输出1)
基于字符串拼接逻辑实现:
yq ea ' . as $item ireduce({}; reduce ($item | path(..)) as $path (.; if ($item | getpath($path)) | type == "string" then setpath($path; (getpath($path) // "") + (if getpath($path) != "" then "," else "" end) + ($item | getpath($path))) else . * $item end ) )' file*.yaml
逻辑说明:
- 对字符串类型的重复键值,直接拼接为逗号分隔的字符串
// ""处理目标路径不存在的情况,避免空值报错- 非字符串类型的键值保持常规合并
内容的提问来源于stack exchange,提问作者Igor
相关产品推荐
相关产品推荐

