合并两个 yaml 文件,以便列表在必要时具有额外的值

merge two yaml files so list has extra values if necessary

在我的 shell 脚本中,有一个命令使用 yaml 文件的部分,我希望这个 yaml 文件根据 [=] 中可访问的变量值略有不同22=]脚本。

yaml文件如下:

name: John
friends:
  - friendName: Bob
    family:
       extended:
          cousins:
             - Sarah
             - Jane
             - Tom
age: 12

然而,根据上述变量的值,我可能还希望 yaml 文件如下(即向 cousins 列表添加更多值):

name: John
friends:
  - friendName: Bob
    family:
       extended:
          cousins:
             - Sarah
             - Jane
             - Tom
             - Arthur
             - Michael
             - Frank
age: 12

我了解 yaml 文件不支持条件语句,理想情况下我不希望在 yaml 文件中重复内容。有没有办法合并两个 yaml 文件,这样如果两个文件中存在相同的列表,它们就会合并(从而实现我想要的向 cousins 列表添加更多值的目标?

Multiply 可以使用变体 *+ 来实现,它连接序列:

yq eval-all 'select(fileIndex == 0) *+ select(fileIndex == 1)' file1.yaml file2.yaml

鉴于输入:

# file1.yaml
---
- one
- two
- three
...
# file2.yaml
---
- three
- four
- five

你会得到

- one
- two
- three
- three
- four
- five

请注意 concatenate 意味着两个列表中存在的任何值都会重复。您对此无能为力,这就是列表的工作方式。如果您不想重复项目,则必须改用具有该语义的集合。在 YAML 中,您通过提供没有值的映射来定义集合:

# file1.yaml
---
? one
? two
? three
...
# file2.yaml
---
? three
? four
? five

对这些应用相同的操作会给你

one:
two:
three:
four:
five:

(是的,yq 无法在此处保留 ? 语法,这对纯集合更好,但语义相同)

但是如果最终的 YAML 必须包含列表怎么办?好吧,我们最初需要集合来进行合并,但之后我们可以将它们转换为序列,例如这些输入:

# file1.yaml
---
some:
  list:
    ? one
    ? two
    ? three
...
# file2.yaml
---
some:
  list:
    ? three
    ? four
    ? five

使用此命令处理:

yq eval-all 'select(fileIndex == 0) *+ select(fileIndex == 1) | .some.list |= keys' file1.yaml file2.yaml

会给你:

some:
  list:
    - one
    - two
    - three
    - four
    - five

但是因为我们可以动态修改数据,所以我们可以制作它,这样我们就可以输入序列,这些序列将被转换为集合,组合,然后重新-写成序列。有了这个输入

# file1.yaml
---
some:
  list:
    - one
    - two
    - three
...
# file2.yaml
---
some:
  list:
    - three
    - four
    - five

和这个命令

yq eval-all '
  (select(fileIndex == 0) | .some.list |= ((.[] | {.: ""}) as $item
    ireduce ({}; . * $item)))
*+
  (select(fileIndex == 1) | .some.list |= ((.[] | {.: ""}) as $item
    ireduce ({}; . * $item)))
| .some.list |= keys' file1.yaml file2.yaml

你得到

some:
  list:
    - one
    - two
    - three
    - four
    - five

现在的问题是:你能证明你的任务如此复杂吗?