是否可以使用一些智能管道和编码来递归合并yaml文件? 在PHP中,我创建了一个数组(每个模块可以添加或更新系统中/的配置节点)。
目标是导出shellcript,它将合并所有单独的模块文件夹'将文件配置为大合并文件。它更快,更高效,例如,当我们通过FTP部署新版本时,客户不需要模块化。
它应该像PHP函数一样:array_merge_recursive
文件系统结构如下:
mod/a/config/sys.yml
mod/a/config/another.yml
mod/b/config/sys.yml
mod/b/config/another.yml
mod/c/config/totally-new.yml
sys/config/sys.yml
Config看起来像:
date:
format:
date_regular: %d-%m-%Y
一个模块可能会这样做:
date:
format:
date_regular: regular dates are boring
date_special: !!!%d-%m-%Y!!!
到目前为止,我有:
#!/bin/bash
#........
cp -R $dir_project/ $dir_to/
for i in $dir_project/mod/*/
do
cp -R "${i}/." $dir_to/sys/
done
这当然会破坏循环中所有现有的配置文件..(其余的系统文件都是唯一命名的)
基本上,我需要一个用于命令行的yaml解析器,以及一个像array_merge_recursive一样的替代方法。然后一个yaml作家输出它合并。我担心我必须开始学习Python,因为bash不会在这个上削减它。
答案 0 :(得分:10)
你可以使用例如perl。下一个oneliner:
perl -MYAML::Merge::Simple=merge_files -MYAML -E 'say Dump merge_files(@ARGV)' f1.yaml f2.yaml
用于下一个输入文件:f1.yaml
date:
epoch: 2342342343
format:
date_regular: "%d-%m-%Y"
f2.yaml
date:
format:
date_regular: regular dates are boring
date_special: "!!!%d-%m-%Y!!!"
打印合并后的结果......
---
date:
epoch: 2342342343
format:
date_regular: regular dates are boring
date_special: '!!!%d-%m-%Y!!!'
因为@Caleb指出该模块现在只是develeloper,所以这里有一个替代品。它有点长,使用两个(但通常可用)模块:
perl -MYAML=LoadFile,Dump -MHash::Merge::Simple=merge -E 'say Dump(merge(map{LoadFile($_)}@ARGV))' f1.yaml f2.yaml
生成与上面相同的内容。
答案 1 :(得分:3)
我推荐yq -m
。 yq是用于yaml的瑞士军刀,与jq(用于JSON)非常相似。
答案 2 :(得分:1)
没有
Bash不支持嵌套数据结构(它的地图只有整数 - >>字符串或字符串 - >字符串),因此无法在内存中表示任意YAML文档。
为此任务使用更强大的语言。
答案 3 :(得分:1)
Bash对此有点延伸(它可以完成,但它很容易出错)。如果您只想从 bash shell调用一些(而不是使用bash函数实际编写合并脚本),那么您有几个选项。
我注意到有一个基于Java的yaml-merge工具,但这并不适合我的想象,所以我一直在寻找。最后,我使用两个工具(yaml2json和jq。
拼凑了一些东西警告:由于JSON的功能是YAML的only a subset,因此对于复杂的YAML结构而言,这不是一个无损过程。它适用于很多简单的键/值/序列场景,但是如果您的输入YAML太过花哨,它会搞砸。在您的数据类型上测试它,看它是否符合您的预期。
使用yaml2json
将您的输入转换为JSON:
yaml2json input1.yml > input1.json
yaml2json input2.yml > input2.json
使用jq
迭代对象并递归合并它们(有关详细信息,请参阅this question and answers)。按重要性的相反顺序列出文件,因为后面的值会破坏之前的值:
jq -s 'reduce .[] as $item({}; . + $item)' input1.json input2.json > merged.json
把它带回YAML:
json2yaml merged.json > merged.yml
如果你想编写脚本,当然通常的bash机制是你的朋友。如果你碰巧像我一样在GNU-Make中,这样的事情就可以解决问题:
.SECONDEXPANSION:
merged.yml: input1.yml input2.yml
json2yaml <(jq -s 'reduce .[] as $$item({}; . + $$item)' $(foreach YAML,$^,<(yaml2json $(YAML)))) > $@
答案 4 :(得分:1)
晚了聚会,但是我也为此写了一个工具:
https://github.com/benprofessionaledition/yamlmerge
它几乎与Ondra的JVM工具相同(它们甚至都被称为“ yaml merge”),主要区别在于它是用Go语言编写的,因此可以编译为〜3MB的二进制文件,而没有任何外部依赖性。我们在Gitlab-CI容器中使用它。
答案 5 :(得分:0)
有一个合并YAML文件的工具-merge-yaml
。
它支持完整的YAML语法,并能够扩展环境变量引用。
我分叉了它,并将其发布为可执行文件.jar
的形式。
https://github.com/OndraZizka/yaml-merge
用法:
./bin/yaml-merge.sh ./*.yml > result.yml
它是用Java编写的,因此您需要安装Java(我认为是8及更高版本)。
(顺便说一句,如果有人想贡献,那就太好了。)
通常,从某种意义上说,该工具并不总是知道您真正想要做什么,合并YAML并不是一件容易的事。您可以采用多种方式合并结构。想想这个例子:
foo:
bar: bar2
baz:
- baz1
---
foo:
bar: bar1
baz:
- baz2
goo: gaz1
几乎没有问题/未知出现:
foo
树是否应替换第一棵树?bar
应该替换第一个baz
还是合并到一个数组中?jq
数组应该替换第一个数组还是将其合并?
等等可能有人反对说可能会有一些默认值,但现实世界中的需求通常需要不同的操作。
用于处理数据结构的其他工具和库通过使用元数据定义方案来解决此问题,例如JAXB或Jackson使用Java批注。
对于此通用工具,这不是一个选择,因此用户将必须通过a)输入数据或b)参数来控制它。 a)不切实际,有时甚至是不可能的,b)乏味并且需要像RewriteEngine on
RewriteCond %{REQUEST_URI} !^/abc/
RewriteRule ^/?(.*)$ /abc/$1 [END]
那样的精美语法。
也就是说,Caleb的答案可能是您需要的。虽然,该解决方案将您的数据减少到JSON所能提供的程度,但是您将失去注释,以多种方式表示长字符串,在YAML中使用JSON等,这并不是太用户友好。