Ansible 2.9中regex_search/regex_findall多字符串匹配结果异常
Ansible 2.9 筛选KVM列表条目问题排查与解决
问题场景
使用Ansible 2.9版本(无法升级基础设施),需从以下kvm_list列表中筛选出以kgit或kes开头的条目:
kvm_list: - abcdefabcfgh.domain.example - deffghabc.domain.example - abcblabla.domain.example - kabcxyz.domain.example - kesanu.domain.example - kesbapo.domain.example - kextoet.domain.example - kptfkom.domain.example - kgitblabla.domain.example - kgitblubblub.domain.example
执行以下任务后,结果意外包含了kextoet.domain.example和kptfkom.domain.example这两个不符合条件的条目:
- name: "get them devtools" hosts: localhost ignore_errors: True tasks: - set_fact: devtools: "{{ kvm_list | string | regex_search('kgit.*|kes.*', multiline=True)}}" - debug: var=devtools
错误输出:
TASK [debug] ************************************************************************************************************************** ok: [localhost] => { "msg":"kesanu.domain.example','kesbapo.domain.example','kextoet.domain.example','kptfkom.domain.example','kgitblabla.domain.example','kgitblubblub.domain.example]" }
错误原因
将列表转为字符串后,格式类似['item1','item2','item3']。原正则kgit.*|kes.*中的.*会匹配任意字符直到换行,导致kes开头的条目后,字符串里的','kextoet...会被.*一并匹配,因为没有限制匹配的是单个完整条目,从而错误包含了中间的其他k开头条目。
解决方法
方法1:使用select+match过滤器(推荐)
Ansible 2.9原生支持select过滤器结合match测试,直接对列表元素逐个筛选,无需转成字符串:
- name: "get them devtools" hosts: localhost ignore_errors: True vars: kvm_list: - abcdefabcfgh.domain.example - deffghabc.domain.example - abcblabla.domain.example - kabcxyz.domain.example - kesanu.domain.example - kesbapo.domain.example - kextoet.domain.example - kptfkom.domain.example - kgitblabla.domain.example - kgitblubblub.domain.example tasks: - set_fact: devtools: "{{ kvm_list | select('match', '^(kgit|kes)') | list }}" - debug: var=devtools
match测试默认验证字符串开头是否匹配正则,^(kgit|kes)明确指定匹配以kgit或kes开头的内容select会过滤出所有符合条件的元素,最后用list转为列表格式
方法2:修正正则表达式(不推荐,仅作兼容参考)
如果坚持使用字符串转义的方式,需修改正则以匹配单个完整条目:
- name: "get them devtools" hosts: localhost ignore_errors: True vars: kvm_list: - abcdefabcfgh.domain.example - deffghabc.domain.example - abcblabla.domain.example - kabcxyz.domain.example - kesanu.domain.example - kesbapo.domain.example - kextoet.domain.example - kptfkom.domain.example - kgitblabla.domain.example - kgitblubblub.domain.example tasks: - set_fact: devtools: "{{ kvm_list | string | regex_findall(\"'((kgit|kes)[^']+)'\") | list }}" - debug: var=devtools
'((kgit|kes)[^']+)'匹配被单引号包裹、以kgit/kes开头且后续不含单引号的内容,确保只匹配单个条目regex_findall提取所有符合条件的内容,得到正确列表
验证结果
两种方法最终都会输出正确的筛选结果:
ok: [localhost] => { "devtools": [ "kesanu.domain.example", "kesbapo.domain.example", "kgitblabla.domain.example", "kgitblubblub.domain.example" ] }
内容的提问来源于stack exchange,提问作者dfs
相关产品推荐
相关产品推荐

