Ansible 2.13与2.9中loop+set_fact行为差异及最佳实践咨询
Ansible版本兼容问题与列表提取最佳实践
原实现的合规性分析
你之前的写法应该是依赖了Ansible 2.9版本中set_fact对Jinja2字符串插值的隐式列表处理,比如类似set_fact: epg_list="{{ epg_list + [item.id] }}"这种写法。这种实现并不合规——因为它没有遵循Ansible官方推荐的变量操作方式,而是依赖了旧版本中未严格规范的行为。在2.13版本中,Ansible对Jinja2表达式的处理更严格,字符串插值会被直接解析为字符串,而非执行列表拼接逻辑,所以才会出现epg_list变成拼接表达式字符串的问题。
循环提取列表值的最佳实践
方法1:用map过滤器一次性提取(推荐)
无需循环,直接通过map过滤器批量提取列表元素的id属性,转换为新列表:
- set_fact: epg_list: "{{ vlan_list | map(attribute='id') | list }}"
这种写法简洁高效,避免了循环中变量累加的版本兼容问题,在Ansible 2.5+版本中都能稳定运行。
方法2:用json_query过滤器提取
如果需要更复杂的嵌套数据提取,json_query是更灵活的选择:
- set_fact: epg_list: "{{ vlan_list | json_query('[].id') }}"
该过滤器基于JMESPath语法,适合处理复杂结构的数据,同样无需循环,版本兼容性好。
方法3:规范的循环累加写法(不推荐,仅作兼容参考)
如果必须用循环实现,要确保列表操作的语法正确,避免字符串插值的坑:
- set_fact: epg_list: "{{ epg_list | default([]) + [item.id] }}" loop: "{{ vlan_list }}"
这里通过default([])初始化空列表,明确执行列表合并操作,而非依赖字符串插值的隐式转换,能在新老版本中保持一致行为。但相比前两种过滤器方法,循环累加的性能更低,尤其是处理大列表时。
内容的提问来源于stack exchange,提问作者O.K.
相关产品推荐
相关产品推荐

