Search code examples
regexloopsansiblegrepansible-2.x

REGEX (regex_search) like Linux EGREP - Show pattern matching lines (with spaces) using multi-pattern/ range using one with_items loop


Ansible / ansible-playbook 2.9.27

I have the following playbook, and I want to show only those lines (from the data structure (i.e. list --> with_items loop) which match a given multi "egrep" like pattern (ex: "pattern1|pattern2|patter3withRange[0-9a-zA-Z]").

How can I achieve this purely in Ansible, possibly using just one with_items / loop?

It would be great:

  • if I don't have to use N no. of nested loops (per pattern/string) --or--
  • I don't have to use a shell one-liner code (egrep "string|ab.*yz|giga").

Here is my Playbook: aks.yml

---
- hosts: localhost
  become: yes
  remote_user: root
  become_user: root
  pre_tasks:
  - name: show pattern matching lines
    #command: 'echo {{ item }} | egrep -i "r[0-9]|goga"'
    ansible.builtin.debug:
      var: "{{ item }}"
    when: ( item | regex_search('r0[0-9]|goga', ignorecase=True))
    with_items:
      - "ar00n_giga"
      - "Schnooka_goga"
      - "lorito_r01_gigaFifa"

Running the playbook gives me:

$ ansible-playbook aks.yml

[WARNING]: provided hosts list is empty, only localhost is available. Note that the implicit localhost does not match 'all'

PLAY [localhost] *************************************************************************************************************************************************************************************************

TASK [Gathering Facts] *******************************************************************************************************************************************************************************************
ok: [localhost]

TASK [show pattern matching lines] *******************************************************************************************************************************************************************************
ok: [localhost] => (item=ar00n_giga) => {
    "ansible_loop_var": "item", 
    "ar00n_giga": "VARIABLE IS NOT DEFINED!", 
    "item": "ar00n_giga"
}

skipping: [localhost] => (item=Schnooka_goga) 

ok: [localhost] => (item=lorito_r01_gigaFifa) => {
    "ansible_loop_var": "item", 
    "item": "lorito_r01_gigaFifa", 
    "lorito_r01_gigaFifa": "VARIABLE IS NOT DEFINED!"
}

PLAY RECAP *******************************************************************************************************************************************************************************************************
localhost                  : ok=2    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0   

I noticed both the "range" [0-9] and multi pattern i.e. using | within regex_search(...) worked!

  • using range r0[0-9] is successfully catching item strings containing both r00 and r01, which is great.
  • using ...|goga (it also catches 2nd line too, which doesn't have r0[0-9] pattern.

But the above code doesn't work if my values have spaces in the with_items: loop i.e. if I add the following:

with_items:
  - "ar00n_giga"
  - "new goga shooga"
  - "Schnooka_goga"
  - "lorito_r01_gigaFifa"

Then, I'm getting the following error message:

...
TASK [show pattern matching lines] *******************************************************************************************************************************************************************************
ok: [localhost] => (item=ar00n_giga) => {
    "ansible_loop_var": "item", 
    "ar00n_giga": "VARIABLE IS NOT DEFINED!", 
    "item": "ar00n_giga"
}
fatal: [localhost]: FAILED! => {"msg": "template error while templating string: expected token 'end of print statement', got 'goga'. String: {{new goga shooga}}"}

PLAY RECAP *******************************************************************************************************************************************************************************************************
localhost                  : ok=1    changed=0    unreachable=0    failed=1    skipped=0    rescued=0    ignored=0   

Solution

  • On RHEL 7.9 with Ansible from the Red Hat Distribution Channel

    ansible --version
    ansible 2.9.27
    ...
      ansible python module location = /usr/lib/python2.7/site-packages/ansible
      executable location = /usr/bin/ansible
      python version = 2.7.5 (default, May 30 2023, 03:38:55) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
    

    a minimal example playbook

    ---
    - hosts: localhost
      become: false
      gather_facts: false
    
      vars:
    
        ITEMS:
          - "ar00n_giga"
          - "new goga shooga"
          - "Schnooka_goga"
          - "lorito_r01_gigaFifa"
    
      tasks:
    
      - name: Show pattern matching lines
        debug:
          msg: "{{ item }}"
        when: ( item | regex_search('r0[0-9]|goga', ignorecase=True))
        loop: "{{ ITEMS }}"
    
      - name: Show pattern matching lines
        debug:
          var: item
        when: ( item | regex_search('r0[0-9]|goga', ignorecase=True))
        loop: "{{ ITEMS }}"
    
      - name: Show pattern matching lines
        debug:
          var: item
        when: ( item | regex_search('r0[0-9]|goga', ignorecase=True))
        with_items:
          - "ar00n_giga"
          - "new goga shooga"
          - "Schnooka_goga"
          - "lorito_r01_gigaFifa"
    

    will result into an output of

    TASK [Show pattern matching lines] *************
    ok: [localhost] => (item=ar00n_giga) =>
      msg: ar00n_giga
    ok: [localhost] => (item=new goga shooga) =>
      msg: new goga shooga
    ok: [localhost] => (item=Schnooka_goga) =>
      msg: Schnooka_goga
    ok: [localhost] => (item=lorito_r01_gigaFifa) =>
      msg: lorito_r01_gigaFifa
    
    TASK [Show pattern matching lines] *************
    ok: [localhost] => (item=ar00n_giga) =>
      ansible_loop_var: item
      item: ar00n_giga
    ok: [localhost] => (item=new goga shooga) =>
      ansible_loop_var: item
      item: new goga shooga
    ok: [localhost] => (item=Schnooka_goga) =>
      ansible_loop_var: item
      item: Schnooka_goga
    ok: [localhost] => (item=lorito_r01_gigaFifa) =>
      ansible_loop_var: item
      item: lorito_r01_gigaFifa
    
    TASK [Show pattern matching lines] *************
    ok: [localhost] => (item=ar00n_giga) =>
      ansible_loop_var: item
      item: ar00n_giga
    ok: [localhost] => (item=new goga shooga) =>
      ansible_loop_var: item
      item: new goga shooga
    ok: [localhost] => (item=Schnooka_goga) =>
      ansible_loop_var: item
      item: Schnooka_goga
    ok: [localhost] => (item=lorito_r01_gigaFifa) =>
      ansible_loop_var: item
      item: lorito_r01_gigaFifa
    

    Same result with RHEL 7.9 and Ansible installed from Python Package Index (PyPI)

    ```bash
    ansible --version
    ...
    ansible [core 2.11.12]
    ...
      python version = 2.7.5 (default, May 30 2023, 03:38:55) [GCC 4.8.5 20150623 (Red Hat 4.8.5-44)]
      jinja version = 2.11.3
      libyaml = True
    

    In short words, I wasn't able to reproduce an error (annot.: constantly).


    The error message you are receiving

    fatal: [localhost]: FAILED! => {"msg": "template error while templating string: expected token 'end of print statement', got 'goga'. String: {{new goga shooga}}"}
    

    is caused by an incorrect syntax in the debug task, the usage of

    var: "{{ item }}"
    

    instead of

    var: item
    

    or

    msg: "{{ item }}"