需要将this link中的复杂.yaml
文件输入bash脚本,该脚本作为在Amazon Linux 2的EC2实例上运行的自动化程序的一部分运行。请注意,{{1}上面链接中的}文件包含许多对象,我需要提取文件中定义的许多对象之一内部定义的环境变量之一。
具体来说,如何将
.yaml
变量的192.168.0.0/16
值提取到bash变量中?
CALICO_IPV4POOL_CIDR
我还阅读了许多其他文章,以及有关解析更平坦,更简单的 - name: CALICO_IPV4POOL_CIDR
value: "192.168.0.0/16"
文件的博客条目,但其他示例都没有显示如何提取{{1}的.yaml
之类的嵌套值}}。
答案 0 :(得分:2)
MYVAR=$(\
curl https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml | \
grep -A 1 CALICO_IPV4POOL_CIDR | \
grep value | \
cut -d ':' -f2 | \
tr -d ' "')
将curl https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml
替换为您要采购的文件。它将通过管道传输到grep -A 1 CALICO_IPV4POOL_CIDR
。这将为您提供两行文本:名称行和值行。它将通过管道传递到grep value
,这现在为我们提供了仅包含值的所需行。它将通过管道传递到cut -d ':' -f2
,后者使用冒号作为定界符,并为我们提供第二个字段。 $(...)
执行附带的脚本,并将其分配给MYVAR
。在此脚本之后,echo $MYVAR
应该产生192.168.0.0/16
。
答案 1 :(得分:2)
如果您能够安装新的依赖项,并计划处理大量Yaml文件,那么yq
是jq的包装,可以处理yaml。它将提供一种安全的(非grep)访问嵌套yaml值的方法。
用法看起来像MY_VALUE=$(yq '.myValue.nested.value' < config-file.yaml)
或者,How can I parse a YAML file from a Linux shell script?具有仅用于bash的解析器,您可以使用该解析器来获取值。
答案 2 :(得分:2)
正确的方法是使用脚本语言和YAML解析库来提取您感兴趣的字段。
这是如何在Python中执行此操作的示例。如果您是真正进行此操作,则可能会将其拆分为多个功能,并具有更好的错误报告功能。从字面上看,这只是为了说明由calico.yaml
格式引起的一些困难,该格式是将多个YAML文档串联在一起,而不仅仅是一个。您还必须遍历文档内部的一些列表,以便提取您感兴趣的字段。
#!/usr/bin/env python3
import yaml
def foo():
with open('/tmp/calico.yaml', 'r') as fil:
docs = yaml.safe_load_all(fil)
doc = None
for candidate in docs:
if candidate["kind"] == "DaemonSet":
doc = candidate
break
else:
raise ValueError("no YAML document of kind DaemonSet")
l1 = doc["spec"]
l2 = l1["template"]
l3 = l2["spec"]
l4 = l3["containers"]
for containers_item in l4:
l5 = containers_item["env"]
env = l5
for entry in env:
if entry["name"] == "CALICO_IPV4POOL_CIDR":
return entry["value"]
raise ValueError("no CALICO_IPV4POOL_CIDR entry")
print(foo())
但是,有时您现在需要一个解决方案 ,shell脚本对此非常有用。
如果您遇到的是API端点,那么YAML通常会被漂亮地打印,因此您可以摆脱在任意YAML上都不起作用的方式提取文本。
类似以下的内容应该相当健壮:
cat </tmp/calico.yaml | grep -A1 CALICO_IPV4POOL_CIDR | grep value: | cut -d: -f2 | tr -d ' "'
尽管最后需要使用正则表达式检查提取的值确实是有效的IPv4 CIDR表示法。
这里的关键是grep -A1 CALICO_IPV4POOL_CIDR
。
您提到的两元素字典(如下所示)将始终显示为一个块,因为它是YAML文档的子树。
- name: CALICO_IPV4POOL_CIDR
value: "192.168.0.0/16"
calico.yaml
中的键通常不按字母顺序排序,但是在{"name": <something>, "value": <something else>}
构造中,name
确实始终出现在value
之前。
答案 3 :(得分:1)
在其他人评论时,建议使用yq
(以及jq
)(如果有)。
然后,请尝试以下操作:
value=$(yq -r 'recurse | select(.name? == "CALICO_IPV4POOL_CIDR") | .value' "calico.yaml")
echo "$value"
输出:
192.168.0.0/16
答案 4 :(得分:0)
您在那里遇到两个问题:
我猜您通过阅读Gregory Nisbett的答案就需要“ DaemonSet”类型的YAML文档。
我将尝试仅使用可能已经在系统上安装的工具,因为您提到要在Bash脚本中执行此操作。我认为您有JQ,因为没有它,在Bash中很难做很多事情!
对于YAML库,我倾向于为此使用Ruby,因为:
建议使用yq,但在这种情况下并没有太大帮助,因为您仍然需要可以提取YAML文档的工具。
已提取文档,我将再次使用Ruby将文件另存为JSON。然后我们可以使用jq。
提取YAML文档
要使用Ruby获取YAML文档并将其另存为JSON:
url=...
curl -s $url | \
ruby -ryaml -rjson -e \
"puts YAML.load_stream(ARGF.read)
.select{|doc| doc['kind']=='DaemonSet'}[0].to_json" \
| jq . > calico.json
进一步的解释:
我通过jq .
传递了该响应,以便将其格式化为便于人类阅读,但实际上并没有必要执行此步骤。我可以在Ruby中做同样的事情,但我猜您希望将Ruby代码保持在最低限度。
选择所需的密钥
要选择密钥,可以使用以下JQ查询:
jq -r \
'.spec.template.spec.containers[].env[] | select(.name=="CALICO_IPV4POOL_CIDR") | .value' \
calico.json
进一步的解释:
spec.template.spec.containers[].env[]
对所有容器及其中的所有环境进行迭代将它们放在一起:
#!/usr/bin/env bash
url='https://docs.projectcalico.org/v3.3/getting-started/kubernetes/installation/hosted/kubernetes-datastore/calico-networking/1.7/calico.yaml'
curl -s $url | \
ruby -ryaml -rjson -e \
"puts YAML.load_stream(ARGF.read)
.select{|doc| doc['kind']=='DaemonSet'}[0].to_json" \
| jq . > calico.json
jq -r \
'.spec.template.spec.containers[].env[] | select(.name=="CALICO_IPV4POOL_CIDR") | .value' \
calico.json
测试:
▶ bash test.sh
192.168.0.0/16