Ansible filter filename list with substring list

Viewed 56

This seems simple enough but I can't find the ansible/jinja way to do it nor the correct keywords to find some pointers.

There's a list of file names (firstlist) (read from a file if it makes anything easier).
There's a second list (secondlist) with partial filenames to filter the first one. This second list can have elements that don't match.

/tmp/filelist.txt contents:

A-ok.txt
B-ok.txt
C-ok.txt

Tasks extract:

- 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 }}"   # <--- need to filter here?

Would result in looping just:

A-ok.txt
C-ok.txt

If secondlist contained the full filename, adding:

when: item in secondlist

would be enough.

It seems select() is half the answer but I can't find the correct test to match the partial filename from the second list

2 Answers
  1. Take your "filter" list (["A", "C", "D"]) and transform it to a regex of chars to look for ("A|C|D") (using regex_escape on each list element for safety).
  2. use the select filter to retain only element that pass the match test (i.e. the regex is found at the beginning of the expression)

In a nutshell, the following playbook:

---
- hosts: localhost
  gather_facts: false

  vars:
    filelist:
      - A-ok.txt
      - B-ok.txt
      - C-ok.txt

    keeplist:
      - A
      - C
      - D

    filteredlist: "{{ filelist | select('match', keeplist | map('regex_replace') | join('|')) }}"

  tasks:
    - debug:
        var: filteredlist

gives:

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

TASK [debug] ***************************************************************************************************************************************************************************************************************************
ok: [localhost] => {
    "filteredlist": [
        "A-ok.txt",
        "C-ok.txt"
    ]
}

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

Note: Posting my final result in answer form as suggested.

After @Zeitounator this is where I ended up:

---
- hosts: localhost
  gather_facts: false

  vars:
    filelist:
      - plugin-test-v1.txt
      - plugin-database.txt
      - C-ok.txt

    keeplist:
      - plugin-database
      - plugin-test
      - plugin-none

    regexp: "{{ keeplist | map('regex_escape') | join('|') }}"

    filteredlist: "{{ filelist | select('match', regexp) }}"

  tasks:
    - name: "print it"
      ansible.builtin.debug:
        msg: "{{ item }}"
      loop: "{{ filteredlist|default(filelist) }}"

Couple points:

  • extracted the regexp in a separate variable because templating inline was giving me troubles with dash in the pattern
  • the loop defaults to the full list if the filter ends up empty

Outputs:

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

TASK [print it] ********************************************************************************************************
ok: [localhost] => (item=plugin-test-v1.txt) => {
    "msg": "plugin-test-v1.txt"
}
ok: [localhost] => (item=plugin-database.txt) => {
    "msg": "plugin-database.txt"
}

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