Is there a way to build up a single string from a list of values using standard Ansible/Jinja2 templating syntax?

47 Views Asked by At

I have a variable that looks something like this:

files:
  - a.yaml
  - b.yaml
  - c.yaml

Using the ansible.builtin.template module, I'd like to build a file which contains the following string:

OPTIONS="--config=a.yaml --config=b.yaml --config.yaml"

I can't hard-code this as I don't always know:

  1. How many files there will actually be
  2. What the names of the files will be

...because they may be set via any one of Ansible's variable setting options (host|group_vars, role defaults etc.). This means I need to "build" it up and then "inject" it into a template somehow.

Is there a way to build up a string from a list like this?

Thanks!

3

There are 3 best solutions below

1
trkmh19 On BEST ANSWER

You can achieve this by using the join filter in Ansible.

Here i provide an example playbook that demonstrates how you can build your desired string from the list of files (not limited to 3 files) using the join filter:

---
- name: Build string from a list in Ansible
  hosts: <your_target_hosts>
  gather_facts: false  # here you can adjust this based on your needs

  tasks:
    - name: Set the list of files
      set_fact:
        files_list:
          - a.yaml
          - b.yaml
          - c.yaml

    - name: Build the OPTIONS string
      set_fact:
        options_string: "--config={{ files_list | join(' --config=') }}"

    - name: Debug the OPTIONS string ( to show the value )
      debug:
        var: options_string

Now, you can use the "options_string" variable in your template module or other tasks as you need

0
larsks On

You can use map and regex_replace, like this:

- hosts: localhost
  gather_facts: false
  vars:
    files:
      - a.yaml
      - b.yaml
      - c.yaml
  tasks:
    - copy:
        dest: myfile.sh
        content: |
          OPTIONS="{{ files | map('regex_replace', '^(.*)$', '--config=\1') | join(' ') }}"

This will create file myfile.sh with content:

OPTIONS="--config=a.yaml --config=b.yaml --config=c.yaml"

0
U880D On

And a thrid generic solution for adding a prefix to list elements with product.

---
- hosts: localhost
  become: false
  gather_facts: false

  vars:

    files:
      - a.yaml
      - b.yaml
      - c.yaml

    prefix_argument: '--config='

  tasks:

  - name: product
    debug:
      msg: OPTION="{{ [prefix_argument] | product(files) | map('join') | list | join(' ') }}"

  - name: join only
    debug:
      msg: OPTION="{{ prefix_argument }}{{ files | join(' ' ~ prefix_argument) }}"

will result into an output of

TASK [product] ****************************************************************
ok: [localhost] =>
  msg: OPTION="--config=a.yaml --config=b.yaml --config=c.yaml"
Thursday 07 March 2024  08:00:10 +0100 (0:00:00.081)       0:00:00.169 ********

TASK [join only] **************************************************************
ok: [localhost] =>
  msg: OPTION="--config=a.yaml --config=b.yaml --config=c.yaml"
Thursday 07 March 2024  08:00:11 +0100 (0:00:00.164)       0:00:00.334 ********

===============================================================================
join only --------------------------------------------------------------- 0.16s
product ----------------------------------------------------------------- 0.08s