Ansible Jinja2正则无法匹配字符串开头问题排查
环境信息
我使用的环境如下:
ansible 2.9.27 ansible python module location = /usr/lib/python2.7/site-packages/ansible executable location = /bin/ansible python version = 2.7.5 (default, May 27 2022, 11:27:32) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
需求与问题
我需要从名为found_routes的列表中移除以"default"开头的元素,生成新列表,但正则匹配字符串开头的操作出现异常。
我的列表内容:
[ u'default via 10.13.99.1 dev bond0.99', u'10.13.101.0/23 dev p1p1.101', u'128.1.66.227 via 10.13.201.1 dev p1p1.201' ]
尝试操作
我先尝试用以下代码过滤:
- name: Populate appended route list set_fact: found_added_routes: "{{ found_routes | select('search', ' via ') | reject('regex', '^default') | list }}"
这段代码无法过滤掉第一个默认路由条目,但改用下面的代码就能生效:
- name: Populate appended route list set_fact: found_added_routes: "{{ found_routes | select('search', ' via ') | reject('regex', '^..default') | list }}"
我想知道:字符串开头存在哪两个不可见字符,导致必须用^..default才能匹配?
调试输出
我的调试代码:
- name: Debug found_routes debug: msg: "Found route list: {{ item }}" loop: "{{ found_routes }}" - name: Debug found_added_routes debug: msg: "Found: {{ item }}" loop: "{{ found_added_routes }}"
成功过滤后的调试输出:
TASK [networks : Debug found_route_list] ********************************************************************************************************************** ok: [server01.example.com] => (item=default via 10.13.99.1 dev bond0.99) => { "msg": "Found route list: default via 10.13.99.1 dev bond0.99" } ok: [server01.example.com] => (item=10.13.101.0/24 dev p1p1.101) => { "msg": "Found route list: 10.13.101.0/24 dev p1p1.101" } ok: [server01.example.com] => (item=128.1.66.227 via 10.13.101.1 dev p1p1.101) => { "msg": "Found route list: 128.1.66.227 via 10.13.101.1 dev p1p1.101" } TASK [networks : Debug found_added_routes] ********************************************************************************************************************** ok: [server01.example.com] => (item=10.13.101.0/24 dev p1p1.101) => { "msg": "Found: 10.13.101.0/24 dev p1p1.101" } ok: [server01.example.com] => (item=128.1.66.227 via 10.13.101.1 dev p1p1.101) => { "msg": "Found: 128.1.66.227 via 10.13.101.1 dev p1p1.101" }
问题分析与解决
你遇到的情况大概率是字符串开头存在UTF-8 BOM(字节顺序标记),也就是\xef\xbb\xbf这三个字节,在Python 2.7的字符串处理逻辑下,可能只体现出前两个字节的影响;另一种可能是从命令输出(比如ip route)获取路由信息时,输出包含了开头的空格、制表符这类不可见空白字符,只是调试输出没有显示出来。
要验证具体是什么字符,可以添加以下调试任务,把字符串转成Base64编码后输出,解码就能看到原始字节:
- name: Debug raw bytes of route items debug: msg: "{{ item | string | b64encode }}" loop: "{{ found_routes }}"
更稳妥的过滤方式,不需要依赖匹配前两个字符,直接用正则匹配任意开头空白后接"default"即可:
- name: Populate appended route list set_fact: found_added_routes: "{{ found_routes | select('search', ' via ') | reject('regex', '^\\s*default') | list }}"
这里\s*会匹配0个或多个空白字符(空格、制表符等),不管开头有没有不可见字符,都能正确过滤默认路由。
内容的提问来源于stack exchange,提问作者Mike S
相关产品推荐
相关产品推荐

