如何在Ansible中使用set_fact创建自定义字典列表?
解决Ansible中set_fact创建字典列表变量的报错问题
问题背景
需要通过set_fact生成一个仅包含path和files字段的字典列表,原始数据previous.results的结构如下:
[ { "path": "/aaa", "files": ["f1.txt", "f2.txt"], "其他字段": "任意值" }, { "path": "/bbb", "files": ["f3.txt"], "其他字段": "任意值" } ]
期望生成的目标变量结构:
[ {"path": "/aaa", "files": ["f1.txt", "f2.txt"]}, {"path": "/bbb", "files": ["f3.txt"]} ]
尝试的代码及报错
使用以下set_fact任务时触发了变量未定义错误:
- name: init ansible.builtin.set_fact: files: "{{ files|default([]) + [ { path: item['path'], files: item.keys() } ] }}" with_items: "{{ previous.results }}"
报错信息:
fatal: [localhost]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'path' is undefined. 'path' is undefined The error appears to be in 'test-playbook.yaml': line 47, column 5, but may be elsewhere in the file depending on the exact syntax problem. The offending line appears to be: - name: init ^ here "}
问题原因及解决方案
报错原因
- Jinja2表达式中,字典的键如果不加引号会被当作变量解析,代码里的
path和files未加引号,Ansible会尝试寻找名为path的变量,导致报错。 item.keys()是错误的取值方式,应该直接提取item['files']字段的内容。
修正后的代码
方案一:循环构建变量
- name: 初始化files变量 ansible.builtin.set_fact: files: "{{ files|default([]) + [ { 'path': item['path'], 'files': item['files'] } ] }}" loop: "{{ previous.results }}"
方案二:用过滤器简化(推荐)
无需循环,直接通过json_query过滤器提取指定字段:
- name: 生成目标字典列表 ansible.builtin.set_fact: files: "{{ previous.results | map('json_query', '{path: path, files: files}') | list }}"
后续双循环创建文件示例
得到files变量后,可通过双循环完成目录创建和文件写入:
- name: 创建目标目录 ansible.builtin.file: path: "{{ item.0.path }}" state: directory loop: "{{ files | subelements('files') }}" - name: 向文件写入内容 ansible.builtin.copy: content: "自定义文件内容" dest: "{{ item.0.path }}/{{ item.1 }}" loop: "{{ files | subelements('files') }}"
内容的提问来源于stack exchange,提问作者sctx
相关产品推荐
相关产品推荐

