Ansible/Jinja2中如何通过子串列表过滤文件名列表
Ansible 按子串列表筛选文件名列表实现方案
需求说明
- 存在两个列表:
firstlist存储完整文件名,可从文件读取生成;secondlist存储用于匹配的文件名子串,允许存在无任何匹配结果的子串元素 - 目标是筛选出
firstlist中包含secondlist内任意一个子串的元素,不需要子串与完整文件名完全匹配
示例场景基础信息:/tmp/filelist.txt 文件内容:
A-ok.txt B-ok.txt C-ok.txt
初始变量值:
firstlist: ['A-ok.txt', 'B-ok.txt', 'C-ok.txt'] secondlist: ['A', 'C', 'D']
预期输出结果:
A-ok.txt C-ok.txt
实现方式
方式1:循环时直接加判断(适合小列表、单次使用场景)
直接在循环任务上添加when条件,利用Jinja2的select过滤器做子串存在判断即可,不需要修改原有变量:
- name: Read filelist command: cat /tmp/filelist.txt register: filelist_results - name: "[FACT] filelist" set_fact: firstlist: "{{ filelist_results.stdout_lines }}" secondlist: ['A', 'C', 'D'] - name: "print it" ansible.builtin.debug: msg: "{{ item }}" loop: "{{ firstlist }}" when: secondlist | select('in', item) | length > 0
逻辑说明:select('in', item)会遍历secondlist的每个元素,判断「子串是否在当前文件名item中」,只要存在至少1个命中的子串,筛选结果长度就大于0,当前item就会被输出。无匹配的子串(比如示例中的'D')不会抛出错误,会自动跳过。
方式2:预过滤生成新列表(适合大列表、结果需要复用场景)
如果列表元素较多,或者筛选后的结果需要在多个任务中使用,可以提前过滤生成独立的筛选列表,减少重复判断的性能消耗:
- name: 生成过滤后的文件列表 set_fact: filtered_list: "{{ firstlist | select(lambda x: secondlist | select('in', x) | list | length > 0) | list }}" - name: "print filtered result" ansible.builtin.debug: msg: "{{ item }}" loop: "{{ filtered_list }}"
如果使用的Ansible版本不支持lambda表达式,可以用兼容性更好的列表推导式写法:
- name: 生成过滤后的文件列表(全版本兼容) set_fact: filtered_list: "{{ [f for f in firstlist if (secondlist | select('in', f) | list | length > 0)] }}"
扩展说明
- 如果需要做大小写不敏感的子串匹配,可以把
select('in', item)替换为select('search', item, ignorecase=True),适配大小写不敏感的文件系统场景 - 不要用
match测试做匹配,match仅从字符串起始位置开始匹配,子串不在文件名开头时会匹配失败
内容的提问来源于stack exchange,提问作者user14168816
相关产品推荐
相关产品推荐

