我希望提供一个结构化的配置文件,它对于非技术用户来说尽可能容易编辑(不幸的是它必须是一个文件),所以我想使用YAML。然而,我找不到任何方法从Unix shell脚本解析这个。
当前回答
Whenever you need a solution for "How to work with YAML/JSON/compatible data from a shell script" which works on just about every OS with Python (*nix, OSX, Windows), consider yamlpath, which provides several command-line tools for reading, writing, searching, and merging YAML, EYAML, JSON, and compatible files. Since just about every OS either comes with Python pre-installed or it is trivial to install, this makes yamlpath highly portable. Even more interesting: this project defines an intuitive path language with very powerful, command-line-friendly syntax that enables accessing one or more nodes.
针对您的具体问题,在使用Python的本地包管理器或您的操作系统的包管理器安装yamlpath之后(yamlpath可以通过RPM对某些操作系统提供):
#!/bin/bash
# Read values directly from YAML (or EYAML, JSON, etc) for use in this shell script:
myShellVar=$(yaml-get --query=any.path.no[matter%how].complex source-file.yaml)
# Use the value any way you need:
echo "Retrieved ${myShellVar}"
# Perhaps change the value and write it back:
myShellVar="New Value"
yaml-set --change=/any/path/no[matter%how]/complex --value="$myShellVar" source-file.yaml
不过,您没有指定数据是一个简单的Scalar值,因此让我们提高赌注。如果你想要的结果是一个数组呢?更有挑战性的是,如果它是一个哈希数组,而你只想要每个结果的一个属性呢?进一步假设您的数据实际上分布在多个YAML文件中,并且您需要在单个查询中获得所有结果。这是一个更有趣的问题。所以,假设你有这两个YAML文件:
文件:data1.yaml
---
baubles:
- name: Doohickey
sku: 0-000-1
price: 4.75
weight: 2.7g
- name: Doodad
sku: 0-000-2
price: 10.5
weight: 5g
- name: Oddball
sku: 0-000-3
price: 25.99
weight: 25kg
文件:data2.yaml
---
baubles:
- name: Fob
sku: 0-000-4
price: 0.99
weight: 18mg
- name: Doohickey
price: 10.5
- name: Oddball
sku: 0-000-3
description: This ball is odd
在应用数据2的更改后,如何仅报告库存中每个项目的sku。Yaml到data1。Yaml,所有从一个shell脚本?试试这个:
#!/bin/bash
baubleSKUs=($(yaml-merge --aoh=deep data1.yaml data2.yaml | yaml-get --query=/baubles/sku -))
for sku in "${baubleSKUs[@]}"; do
echo "Found bauble SKU: ${sku}"
done
你只需要几行代码就能得到你想要的东西:
Found bauble SKU: 0-000-1
Found bauble SKU: 0-000-2
Found bauble SKU: 0-000-3
Found bauble SKU: 0-000-4
如您所见,yamlpath将非常复杂的问题转化为简单的解决方案。注意,整个查询是作为一个流处理的;查询没有更改YAML文件,也没有临时文件。
I realize this is "yet another tool to solve the same question" but after reading the other answers here, yamlpath appears more portable and robust than most alternatives. It also fully understands YAML/JSON/compatible files and it does not need to convert YAML to JSON to perform requested operations. As such, comments within the original YAML file are preserved whenever you need to change data in the source YAML file. Like some alternatives, yamlpath is also portable across OSes. More importantly, yamlpath defines a query language that is extremely powerful, enabling very specialized/filtered data queries. It can even operate against results from disparate parts of the file in a single query.
If you want to get or set many values in the data at once -- including complex data like hashes/arrays/maps/lists -- yamlpath can do that. Want a value but don't know precisely where it is in the document? yamlpath can find it and give you the exact path(s). Need to merge multiple data file together, including from STDIN? yamlpath does that, too. Further, yamlpath fully comprehends YAML anchors and their aliases, always giving or changing exactly the data you expect whether it is a concrete or referenced value.
免责声明:我编写并维护了yamlpath,它是基于ruamel的。yaml是基于PyYAML的。因此,yamlpath完全符合标准。
其他回答
你可以用golang写成yq的等价形式:
./go-yg -yamlFile /home/user/dev/ansible-firefox/defaults/main.yml -key
firefox_version
返回:
62.0.3
yq是一个轻量级、可移植的命令行YAML处理器
这个项目的目标是yaml文件的jq或sed。
(https://github.com/mikefarah/yq #自述)
作为示例(直接从文档中窃取),给出一个示例。Yaml文件:
---
bob:
item1:
cats: bananas
item2:
cats: apples
then
yq eval '.bob.*.cats' sample.yaml
将输出
- bananas
- apples
我已经用python编写了shyaml,用于从shell命令行查询YAML。
概述:
$ pip install shyaml ## installation
示例的YAML文件(具有复杂的功能):
$ cat <<EOF > test.yaml
name: "MyName !!"
subvalue:
how-much: 1.1
things:
- first
- second
- third
other-things: [a, b, c]
maintainer: "Valentin Lab"
description: |
Multiline description:
Line 1
Line 2
EOF
基本的查询:
$ cat test.yaml | shyaml get-value subvalue.maintainer
Valentin Lab
更复杂的循环查询复杂的值:
$ cat test.yaml | shyaml values-0 | \
while read -r -d $'\0' value; do
echo "RECEIVED: '$value'"
done
RECEIVED: '1.1'
RECEIVED: '- first
- second
- third'
RECEIVED: '2'
RECEIVED: 'Valentin Lab'
RECEIVED: 'Multiline description:
Line 1
Line 2'
以下几个要点:
all YAML types and syntax oddities are correctly handled, as multiline, quoted strings, inline sequences... \0 padded output is available for solid multiline entry manipulation. simple dotted notation to select sub-values (ie: subvalue.maintainer is a valid key). access by index is provided to sequences (ie: subvalue.things.-1 is the last element of the subvalue.things sequence.) access to all sequence/structs elements in one go for use in bash loops. you can output whole subpart of a YAML file as ... YAML, which blend well for further manipulations with shyaml.
更多的示例和文档可以在shyaml github页面或shyaml PyPI页面上找到。
考虑到Python3和PyYAML是非常容易满足的依赖关系,下面的代码可能会有所帮助:
yaml() {
python3 -c "import yaml;print(yaml.safe_load(open('$1'))$2)"
}
VALUE=$(yaml ~/my_yaml_file.yaml "['a_key']")
我知道我的回答很具体,但是如果已经安装了PHP和Symfony,那么使用Symfony的YAML解析器会非常方便。
例如:
php -r "require '$SYMFONY_ROOT_PATH/vendor/autoload.php'; \
var_dump(\Symfony\Component\Yaml\Yaml::parse(file_get_contents('$YAML_FILE_PATH')));"
这里我只是简单地使用var_dump来输出解析后的数组,当然你还可以做更多…:)
推荐文章
- 查看PS命令的全部输出
- 确保一次只运行一个shell脚本实例的快速方法
- 如何从同一个YAML文件的其他地方引用YAML“设置”?
- 如何在Makefile中设置子进程的环境变量
- 如何让“wc -l”打印没有文件名的行数?
- 有效地测试Linux上的端口是否打开?
- 如何从另一个文件A中删除文件B中出现的行?
- Shell脚本删除超过n天的目录
- 如何检查shell脚本中是否存在命令?
- 如何使用查找命令从列表中查找所有具有扩展名的文件?
- 如何打破一个循环在Bash?
- 如何合并2 JSON对象从2个文件使用jq?
- 删除Bash脚本中的重复条目
- 如何将Bash命令的输出分配给变量?
- PHP中的异步shell执行器