我有一个字典列表,其中每个字典都有相同的键,只是值不同。我可以循环遍历列表并获取我想要的“ip”属性,但这是一个很大的列表,我想知道是否有一个查找命令可以更好地工作。以下是列表的一个小示例:
"current": [
{
"fvSubnet": {
"attributes": {
"annotation": "",
"childAction": "",
"configIssues": "",
"ctrl": "",
"debugMessage": "",
"descr": "",
"dn": "uni/tn-MYBD/BD-VLAN_10/subnet-[114.66.71.17/28]",
"extMngdBy": "",
"ip": "114.66.71.17/28",
"ipDPLearning": "enabled",
"lcOwn": "local",
"modTs": "2023-07-11T08:18:19.497+00:00",
"monPolDn": "uni/tn-common/monepg-default",
"name": "",
"nameAlias": "",
"preferred": "yes",
"scope": "public",
"status": "",
"uid": "19044",
"userdom": ":all:",
"virtual": "yes"
}
}
},
{
"fvSubnet": {
"attributes": {
"annotation": "",
"childAction": "",
"configIssues": "",
"ctrl": "nd",
"debugMessage": "",
"descr": "",
"dn": "uni/tn-MYBD/BD-VLAN_20/subnet-[1008:125:0:e56::1/64]",
"extMngdBy": "",
"ip": "1008:125:0:e56::1/64",
"ipDPLearning": "enabled",
"lcOwn": "local",
"modTs": "2023-07-11T08:18:19.497+00:00",
"monPolDn": "uni/tn-common/monepg-default",
"name": "",
"nameAlias": "",
"preferred": "no",
"scope": "public",
"status": "",
"uid": "19044",
"userdom": ":all:",
"virtual": "no"
}
}
}
]
我只对每个字典的“ip”属性感兴趣。我可以进行查找并获取所有属性吗?还是需要循环遍历字典列表?
答案1
任何不需要在数据上运行模块的数据转换都可以作为过滤表达式更有效地完成。
为了方便起见,为表达式创建一个新变量(尽管想出一个更好的名字):
fvSubnet_ip: "{{ current | map(attribute='fvSubnet.attributes.ip') }}"
Jinja 内置地图过滤器可以为您获取一个属性,因此将字典列表变成一个列表。不太明显的是,可以使用点符号来查看字典的字典。比链接多个映射函数更紧凑的语法。
转储 fvSubnet_ip 确实会导致
[
"114.66.71.17/28",
"1008:125:0:e56::1/64"
]
如果还需要基于其他属性进行过滤,请考虑另一个内置过滤器,选择属性。首先选择对象,然后提取所需的属性。这就是 Jinja 过滤器可以链接在一起的原因。
由于这些是 IP 子网,请注意 ipaddr 系列过滤器存在是为了做有用的事情。 ansible-doc -t filter ipaddr
答案2
您可以使用json_query
过滤器,使用路径提取 JSON 值。
请注意,您必须jmespath
在主机上安装。您可以使用pip
:
pip install jmespath
然后我们可以使用下面的模板:
"{{ current | community.general.json_query('[*].fvSubnet.attributes.ip') }}"
包含您的数据的示例调试剧本:
---
- hosts: localhost
vars:
current: [
{
"fvSubnet": {
"attributes": {
"annotation": "",
"childAction": "",
"configIssues": "",
"ctrl": "",
"debugMessage": "",
"descr": "",
"dn": "uni/tn-MYBD/BD-VLAN_10/subnet-[114.66.71.17/28]",
"extMngdBy": "",
"ip": "114.66.71.17/28",
"ipDPLearning": "enabled",
"lcOwn": "local",
"modTs": "2023-07-11T08:18:19.497+00:00",
"monPolDn": "uni/tn-common/monepg-default",
"name": "",
"nameAlias": "",
"preferred": "yes",
"scope": "public",
"status": "",
"uid": "19044",
"userdom": ":all:",
"virtual": "yes"
}
}
},
{
"fvSubnet": {
"attributes": {
"annotation": "",
"childAction": "",
"configIssues": "",
"ctrl": "nd",
"debugMessage": "",
"descr": "",
"dn": "uni/tn-MYBD/BD-VLAN_20/subnet-[1008:125:0:e56::1/64]",
"extMngdBy": "",
"ip": "1008:125:0:e56::1/64",
"ipDPLearning": "enabled",
"lcOwn": "local",
"modTs": "2023-07-11T08:18:19.497+00:00",
"monPolDn": "uni/tn-common/monepg-default",
"name": "",
"nameAlias": "",
"preferred": "no",
"scope": "public",
"status": "",
"uid": "19044",
"userdom": ":all:",
"virtual": "no"
}
}
}
]
tasks:
- name: Debug
debug:
msg: "{{ current | community.general.json_query('[*].fvSubnet.attributes.ip') }}"
输出:
❯ ansible-playbook demo.yaml
[WARNING]: No inventory was parsed, only implicit localhost is available
[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match
'all'
PLAY [localhost] **********************************************************************************************************
TASK [Gathering Facts] ****************************************************************************************************
ok: [localhost]
TASK [Debug] **************************************************************************************************************
ok: [localhost] => {
"msg": [
"114.66.71.17/28",
"1008:125:0:e56::1/64"
]
}
PLAY RECAP ****************************************************************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0