【问题标题】:Ansible: How do I test/filter items in a list using a regex?Ansible:如何使用正则表达式测试/过滤列表中的项目?
【发布时间】:2022-12-13 12:00:01
【问题描述】:

在一个可靠的剧本中,我想仅当用户名或后跟后缀“.A”的用户名出现在另一个列表中时,才对一个列表中的一组用户名循环执行任务。

失败的示例剧本:

---
- hosts: localhost
  vars:
    - users1:
        - alice
        - alice.A
        - bob
        - santa
    - users2:
        - alice
  tasks:
    - debug:
        msg: "Do something for {{ item }} realname {{ item | regex_replace('^([a-z]+)\\.[aA]$', '\\1') }}"
      loop: "{{ users1 }}"
      when:
        - "item | regex_replace('^([a-z]+)\\.[aA]$', '\\1') in users2"

此版本跳过 alice.A,而任务本身中的 regex_replace 过滤器按预期返回 alice

实际输出:

TASK [debug] ***************
ok: [localhost] => (item=alice) => {}

MSG:

Do something for alice realname alice
skipping: [localhost] => (item=alice.A)
skipping: [localhost] => (item=bob)
skipping: [localhost] => (item=santa)

期望的输出:

TASK [debug] ***************
ok: [localhost] => (item=alice) => {}

MSG:

Do something for alice realname alice
Do something for alice.A realname alice
skipping: [localhost] => (item=bob)
skipping: [localhost] => (item=santa)

是否可以对要测试的项目应用过滤器? 如果没有,有没有办法使用map()之类的东西来复制users2列表中的条目,并为每个项目附加“.A”后缀?

当我尝试过的条件都失败时:

    when: ("item in users2 | flatten(1)") or
      ("item|regex_search('\.A$')")

    when: 
      - "item | regex_replace('^([a-z]+\\.[a-z]+).[aA]$', '\\1') in users | flatten(1)"

    when: 
      - "item in users | flatten(1) | map('regex_replace','^([a-z]+\\.[a-z]+)$', '\\1.A')"

    when: 
      - "item | map('regex_replace','^([a-z]+\\.[a-z]+).[aA]$', '\\1') in users | flatten(1)"

    when: 
      - "item|map('upper') in users | flatten(1)"

最后一个只是检查测试的项目是否被过滤器修改。 (这不是 AFAICT。)

【问题讨论】:

    标签: filter ansible conditional-statements


    【解决方案1】:

    不需要正则表达式。使用splitext获取真正的名字并测试它在列表中的存在用户2

        - debug:
            msg: "Do something for {{ item }} realname {{ realname }}."
          loop: "{{ users1 }}"
          when: realname in users2
          vars:
            realname: "{{ item|splitext|first }}"
    

    给出了预期的结果

    TASK [debug] ********************************************************
    ok: [localhost] => (item=alice) => 
      msg: Do something for alice realname alice.
    ok: [localhost] => (item=alice.A) => 
      msg: Do something for alice.A realname alice.
    skipping: [localhost] => (item=bob) 
    skipping: [localhost] => (item=santa)
    

    你说你

    仅当用户名或用户名后跟后缀“.A”时,才希望对一个列表中的一组用户名循环执行任务

    上面的任务将接受任何后缀,而不仅仅是“.A”。还测试后缀以修复它。下面的任务给出了相同的结果

        - debug:
            msg: "Do something for {{ item }} realname {{ realname }}."
          loop: "{{ users1 }}"
          when:
            - realname in users2
            - suffix == '.A'
          vars:
            arr: "{{ item|splitext|list }}"
            realname: "{{ arr.0 }}"
            suffix: "{{ arr.1|default('.A', true) }}"
    

    参见Providing default values


    如果你想使用正则表达式改变下面的变量。这将给出相同的结果。

        - debug:
            msg: "Do something for {{ item }} realname {{ realname }}."
          loop: "{{ users1 }}"
          when: realname in users2
          vars:
            realname: "{{ item|regex_replace(regex, replace) }}"
            regex: '^(.*?)(.A)*$'
            replace: ''
    

    更新

    或者,先创建结构并简化任务中的代码

        users3_str: |
          {% for u in users1 %}
          {% set arr = u|splitext|list %}
          - name: {{ u }}
            realname: {{ arr.0 }}
            suffix: {{ arr.1|default('.A', true) }}
          {% endfor %}
        users3: "{{ users3_str|from_yaml }}"
    

      users3:
        - {name: alice, realname: alice, suffix: .A}
        - {name: alice.A, realname: alice, suffix: .A}
        - {name: bob, realname: bob, suffix: .A}
        - {name: santa, realname: santa, suffix: .A}
    

    然后,下面的任务给出相同的结果

        - debug:
            msg: "Do something for {{ item.name }} realname {{ item.realname }}."
          loop: "{{ users3|selectattr('realname', 'in', users2) }}"
    
    
        - debug:
            msg: "Do something for {{ item.name }} realname {{ item.realname }}."
          loop: "{{ users3|selectattr('realname', 'in', users2)|
                           selectattr('suffix', '==', '.A') }}"
    

    【讨论】:

    • 谢谢,从来没有想过以这种方式使用 splitext!由于原始问题更复杂,我最终使用了解决方案的正则表达式部分。但也有使用正则表达式和替换 vars 使整个事情更具可读性。太糟糕了,关于所有这些过滤器的详细信息,ansible 文档非常匮乏。以及整体上正确的语法/句法。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-01
    • 1970-01-01
    相关资源
    最近更新 更多