Ansible set_fact循环首次迭代未模板化变量报错排查修复
问题根因
故障与var_list的初始定义无关,完全由my_list的构建逻辑错误导致:
- 原代码在
set_fact的赋值逻辑外层已经使用{{ }}包裹Jinja2表达式,内层拼接的字符串中又嵌套了第二层{{ item }}模板标记。Ansible的Jinja2渲染器不会对表达式内部的字符串字面量做递归渲染,导致最后一轮循环追加的列表元素保留了未渲染的{{ item }}原始文本。 - 循环任务执行完成后,临时循环变量
item会被销毁,后续任务读取my_list时尝试渲染残留的{{ item }}标记,找不到对应变量就会触发报错,最终导致debug输出异常、synchronize任务执行失败。
修复方案
有两种常用修复方式,推荐优先使用无循环的过滤器写法,执行效率更高:
方式1:修正字符串拼接逻辑(保留原有循环结构)
Jinja2中不要嵌套{{ }}标记,使用~作为字符串连接符直接引用item变量即可,修改循环追加的配置行:
- name: Add variables to list set_fact: my_list: "{{ my_list + ['--exclude ' ~ item ~ '.yaml'] }}" loop: "{{ var_list }}"
方式2:使用过滤器一次性生成列表(推荐)
去掉初始化空列表、循环追加两个任务,直接通过map过滤器批量生成目标列表,避免循环拼接的渲染问题:
- name: Build rsync exclude options set_fact: my_list: "{{ var_list | map('regex_replace', '^(.*)$', '--exclude \\1.yaml') | list }}"
修复后完整Playbook示例
- name: Quick Test Script hosts: servers vars: var_list: - AAA - BBB - CCC - DDD tasks: - name: Build rsync exclude options set_fact: my_list: "{{ var_list | map('regex_replace', '^(.*)$', '--exclude \\1.yaml') | list }}" - name: List of rsync_opts debug: var: my_list - name: Deploy files synchronize: src: ~/ansible dest: "{{ ansible_env.HOME }}/test" archive: false checksum: true owner: false group: false recursive: true links: true times: true delete: true rsync_opts: "{{ my_list }}"
执行后会得到预期的列表值:['--exclude AAA.yaml', '--exclude BBB.yaml', '--exclude CCC.yaml', '--exclude DDD.yaml'],synchronize模块可正常读取参数执行。
内容的提问来源于stack exchange,提问作者RedPeasant
相关产品推荐
相关产品推荐

