You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Ansible多when条件合并字典列表时merged_list未定义问题

问题描述

我现有两个字典列表,结构如下:
第一个列表(list1):

list1: 
[
{
    "_ref": "LAB1/1/4094",
    "vlan_id": 12,
    "vlan_name": "test_vlan_1",
    "vlan_subnet": "192.168.1.0/28",
    "vlan_vrf": "vrf_1"
},
{
    "_ref": "LAB2/1/4094",
    "vlan_id": 12,
    "vlan_name": "test_vlan_1",
    "vlan_subnet": "192.168.2.0/28",
    "vlan_vrf": "vrf_1"
}
]

第二个列表(list2):

list2:
[
{
    "_ref": "LAB1/1/4094",
    "vlan_id": "12",
    "vlan_name": "test_vlan_1",
    "vlan_ref": "vlan/ZG5zLnZsYW4kLmNvbS5pbmZvYmxveC5kbnMudmxhbl92aWV3JElORlJBTEFCLjEuNDA5NC4xMg:LAB1/test_vlan_1/12"
}
]

我最初编写的合并任务代码如下:

- name: merge lists final
  set_fact:
    merged_list: "{{ merged_list|default([]) + [ item[0] | union(item[1]) ] }}"
  when: item[0]._ref == item[1]._ref and item[0].vlan_id == item[1].vlan_id and item[0].vlan_name == item[1].vlan_name
  loop: "{{ query('nested', list1, list2) }}"
- name: print results
  debug:
    var: merged_list

执行后得到如下报错输出:

TASK [print results] ***********************************************************
ok: [localhost] => {
    "merged_list": "VARIABLE IS NOT DEFINED!"
}

期望输出:list2条目与list1第一个字典条目匹配,需将二者合并,最终输出既要包含匹配后的合并条目,也要保留list1中未匹配的第二个条目,结构如下:

merged_list:
[
{
    "_ref": "LAB1/1/4094",
    "vlan_id": 12,
    "vlan_name": "test_vlan_1",
    "vlan_subnet": "192.168.1.0/28",
    "vlan_vrf": "vrf_1",
    "vlan_ref": "vlan/ZG5zLnZsYW4kLmNvbS5pbmZvYmxveC5kbnMudmxhbl92aWV3JElORlJBTEFCLjEuNDA5NC4xMg:LAB1/test_vlan_1/12"
},
{
    "_ref": "LAB2/1/4094",
    "vlan_id": 12,
    "vlan_name": "test_vlan_1",
    "vlan_subnet": "192.168.2.0/28",
    "vlan_vrf": "vrf_1"
}
]

我初步判断when: item[0]._ref == item[1]._ref and item[0].vlan_id == item[1].vlan_id and item[0].vlan_name == item[1].vlan_name条件未按预期生效,请问该如何调整才能得到符合预期的merged_list结果?

问题原因

你判断的方向没错,原写法跑不通有两个硬问题:

  • 类型不匹配导致条件永远不成立:list1里的vlan_id是整数12,list2里的vlan_id是字符串"12",Ansible做相等判断时不会自动做类型转换,12 == "12"直接返回false,所以when条件一次都没满足过,set_fact任务从来没执行过,merged_list根本没被创建,最后打印自然报变量未定义。
  • 逻辑本身漏了未匹配条目:就算你把类型问题修了让条件能命中,原嵌套循环的逻辑只会把两个列表匹配成功的条目加进结果,list1里LAB2那条没有对应list2匹配项的条目,根本不会被写入结果,最后输出会缺数据。
修复方案

不用嵌套循环,直接遍历list1逐行匹配合并即可,逻辑简单还不会漏数据:

- name: 初始化合并结果列表
  set_fact:
    merged_list: []

- name: 逐行合并两个列表
  set_fact:
    merged_list: "{{ merged_list + [ current_item | combine(matched_item | default({})) ] }}"
  loop: "{{ list1 }}"
  vars:
    current_item: "{{ item }}"
    # 匹配时把vlan_id统一转成字符串,解决类型不一致问题
    matched_item: "{{ list2 | selectattr('_ref', '==', current_item._ref) | selectattr('vlan_name', '==', current_item.vlan_name) | selectattr('vlan_id', '==', current_item.vlan_id | string) | first | default({}) }}"

- name: 打印合并结果
  debug:
    var: merged_list

如果后续遇到vlan_id两边类型随机的场景,也可以把两边都转成整数比较,把matched_item定义里的判断改成selectattr('vlan_id', 'int', '==', current_item.vlan_id | int)即可,兼容性更强。

这个写法的逻辑是:

  • 以list1为基准遍历,所有list1的条目都会被保留,不会丢数据
  • 每处理一条list1的条目,就去list2里找符合三个匹配条件的项,匹配时统一vlan_id类型,避免类型不匹配问题
  • 找到匹配项就把list2的字段合并到当前条目里,找不到就合并空字典,保留list1原条目内容
  • 提前初始化merged_list为空列表,不会出现变量未定义的问题,最终输出和你期望的结构完全一致。

内容的提问来源于stack exchange,提问作者netv

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 02:36:27