Formatting multiple lines using variable as loop

I have a playbook variable output as below

debug:
msg: “{{my_var}}}”

TASK [debug] **************************************************************************************************************************
ok: [localhost] => {
“msg”: [
“line1 has , color-red, in its middle”
“line2 has, color-blue, in its middle”
“line3 has, color-orange, in its middle”
]
}

I want to use the output lines as an input for another variable using set_fact , as like below .

  • name: Filtering the color data
    ansible.builtin.set_fact:
    new_var: “{{ item.split(‘,’)[1] }}”
    loop: “{{ var1 }}”

and I am looking for the data like below
color-red
color-blue
color-orange

  • debug:
    var: new_var
    gives only color-red

But my var1 looping process the first line only in from the my_var and not the next 2 lines.
This is an example and I may expect lines from my_var from 0 to 100’s.

How to print the columnof output) with multiple lines ??

In the code below, note that “range(my_var | length)” is equivalent to “[0, 1, 2]”.

In the set_fact, we don’t “loop” the task; rather we loop over the data within the jinja2 expression by using the map filter.

utoddl@tango:~/ansible**$ cat veera01.yml**
---
# veera01.yml
- name: Jinja expressions
  hosts: localhost
  gather_facts: false
  vars:
    my_var:
      - "line1 has , color-red, in  its   middle"
      - "line2 has,   color-blue,   in its middle"
      - "line3 has,  color-orange, in its middle"
  tasks:
    - name: Split and trim parts from my_var
      ansible.builtin.debug:
        msg: "{{ my_var | map('split', ',') | map('map', 'trim') }}"

    - name: Extract the "color-*" parts from my_var
      ansible.builtin.debug:
        msg: "{{ range(my_var | length) | map('extract', (my_var | map('split', ',') | map('map', 'trim')), [1]) }}"

    - name: Same but as set_fact
      ansible.builtin.set_fact:
        new_var: "{{ range(my_var | length) | map('extract', (my_var | map('split', ',') | map('map', 'trim')), [1]) }}"

utoddl@tango:~/ansible**$ ansible-playbook veera01.yml -v**
Using /etc/ansible/ansible.cfg as config file

PLAY [Jinja expressions] **********************************************

TASK [Split and trim parts from my_var] *******************************
ok: [localhost] => 
  msg:
  - - line1 has
    - color-red
    - in  its   middle
  - - line2 has
    - color-blue
    - in its middle
  - - line3 has
    - color-orange
    - in its middle

TASK [Extract the "color-*" parts from my_var] ************************
ok: [localhost] => 
  msg:
  - color-red
  - color-blue
  - color-orange

TASK [Same but as set_fact] *******************************************
ok: [localhost] => changed=false 
  ansible_facts:
    new_var:
    - color-red
    - color-blue
    - color-orange

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

Hi Todd Lewis,

Thanks . I am able to understand it . However the split happens based on ‘,’ , and then we remove the quotes with map(‘map’, ‘trim’)) and align the lines with range.
However assuming split with delimiter as comma, when i try to replace 1 with 0 the output is [msg: “{{ range(my_var | length) | map(‘extract’, (my_var | map(‘split’, ‘,’) | map(‘map’, ‘trim’)), [0]) }}”]

ok: [localhost] =>
msg:

  • line1 has
  • line2 has
  • line3 has

and when tried to add [0 1] in the end [msg: “{{ range(my_var | length) | map(‘extract’, (my_var | map(‘split’, ‘,’) | map(‘map’, ‘trim’)), [0 1]) }}”]
it printsok: [localhost] =>
msg:

  • i
  • i
  • i

that is second character in the word line[0]. Is not the split breaks the words with (‘,’)?
How to print all the available column? instead of 1( yes the full file without a comma now )
Actually I am trying to print like below

line1 has color-red
line2 has color-blue
line3 has color-orange

You said, “However the split happens based on ‘,’ , and then we remove the quotes with map(‘map’, ‘trim’)) and align the lines with range.”

It’s true that “split(‘,’)” will split a string containing commas into a list of strings. But the trim filter does nothing with quotes.

Rather, “trim” removes leading and trailing spaces from the string piped into it:
a_string | trim

Further, “map(‘trim’)” removes leading and trailing spaces from each string of the list of strings passed to it:
[str0, str1, str2] | map(‘trim’)

Finally, “map(‘map’, ‘trim’)” trims strings two levels deep in lists:
[[sa0, sa1], [sb0, bs1], [sc0, sc1]] | map(‘map’, ‘trim’)

Quotes never play into it. In fact, in what you initially posted, and in my response, the string data contain no quotes.

Also, “range” isn’t to align anything. It provides the necessary first parameter to the “extract” filter.

However assuming split with delimiter as comma, when i try to replace 1 with 0 the output is [msg: “{{ range(my_var | length) | map(‘extract’, (my_var | map(‘split’, ‘,’) | map(‘map’, ‘trim’)), [0]) }}”]

Yes, you changed the “1” to a “0”, so you get the first (index=0) item in the list produced by the split.

When it was “1”, you got the second item (index=1) in each list produced by the split, that is “color-red”, “color-blue”, and “color-orange”. From your initial post, that’s what I thought you wanted.

If what you really want is this:
new_var:

  • line1 has color-red
  • line2 has color-blue
  • line3 has color-orange
    then you can use this instead:
    - name: First and Second parts from split on comma
      ansible.builtin.set_fact:
        new_var: "{{ my_var | map('regex_replace', '^([^,]*),([^,]*),.*', '\1 \2') | map('regex_replace', ' +', ' ') }}"

Thanks Todd for the details …