Command with 'creates' is not idempotent when using filenames with square brackets

Viewed 189

I have a task that creates multiple files, if they not exists. It works, until a filename is used as item that contains a pair of square brackets. I've tried to escape with backslashes and {% raw %} tags, but it does not work.

Test playbook:

---
- name: Test playbook
  hosts: localhost
  gather_facts: no

  tasks:
  - name: Testfile
    ansible.builtin.command:
      cmd: 'touch ~/{{ item }}'
    args:
      creates: "~/{{ item }}"
    with_items:
      - 'test1.txt' # works
      - 'tes[t2.txt' # works
      - 'test3].txt' # works
      - 'tes[t4].txt' # DOESNT WORK

First run:

changed: [localhost] => (item=test1.txt)
changed: [localhost] => (item=tes[t2.txt)
changed: [localhost] => (item=test3].txt)
changed: [localhost] => (item=tes[t4].txt)

Consecutive runs:

ok: [localhost] => (item=test1.txt)
ok: [localhost] => (item=tes[t2.txt)
ok: [localhost] => (item=test3].txt)
changed: [localhost] => (item=tes[t4].txt)

Folder content:

ls ~/tes*
'/home/user/tes[t2.txt'  '/home/user/tes[t4].txt'   /home/user/test1.txt   /home/user/test3].txt

Environment:

  • Ubuntu 20 (via WSL2)
  • ansible [core 2.12.1]

Is this a bug, or is there any way to escape the characters so that the task is fully idempotent?

1 Answers

The problem is due to the fact that creates can handle glob syntax (highlighted by @Jack). In glob syntax [ has a special meaning and need to be escaped. I did manage to do it only manually by escaping the [ through this Jinja2 filter {{ item|replace('[', '[[]') }}. I did not found an equivalent convenient filter equivalent to Python glob.escape. However it works!

- name: Test playbook
  hosts: localhost
  gather_facts: no

  tasks:
  - name: Testfile
    ansible.builtin.command:
      cmd: "touch ~/{{ item }}"
    args:
      creates: "~/{{ item|replace('[', '[[]') }}"
    with_items:
      - 'test1.txt' # works
      - 'tes[t2.txt' # works
      - 'test3].txt' # works
      - 'tes[t4].txt' # DOESNT WORK

Further reading on glob escaping -> glob and bracket characters ('[]').

Related