How to join a list of strings in Ansible?
Asked Answered
D

2

59

In Ansible, I have a list of strings that I want to join with newline characters to create a string, that when written to a file, becomes a series of lines. However, when I use the join() filter, it works on the inner list, the characters in the strings, and not on the outer list, the strings themselves. Here's my sample code:

# Usage: ansible-playbook tst3.yaml --limit <GRP>
---
- hosts: all
  remote_user: root

  tasks:

  - name: Create the list
    set_fact:
        my_item: "{{ item }}"
    with_items:
      - "One fish"
      - "Two fish"
      - "Red fish"
      - "Blue fish"
    register: my_item_result

  - name: Extract items and turn into a list
    set_fact:
        my_list: "{{ my_item_result.results | map(attribute='ansible_facts.my_item') | list }}"

  - name: Examine the list
    debug:
        msg: "{{ my_list }}"

  - name: Concatenate the public keys
    set_fact:
        my_joined_list: "{{ item | join('\n') }}"
    with_items:
      - "{{ my_list }}"

  - name: Examine the joined string
    debug:
        msg: "{{ my_joined_list }}"

I want to get output that looks like:

One fish
Two fish
Red fish
Blue Fish

What I get instead is:

TASK: [Examine the joined string] *********************************************
ok: [hana-np-11.cisco.com] => {
    "msg": "B\nl\nu\ne\n \nf\ni\ns\nh"
}
ok: [hana-np-12.cisco.com] => {
    "msg": "B\nl\nu\ne\n \nf\ni\ns\nh"
}
ok: [hana-np-13.cisco.com] => {
    "msg": "B\nl\nu\ne\n \nf\ni\ns\nh"
}
ok: [hana-np-14.cisco.com] => {
    "msg": "B\nl\nu\ne\n \nf\ni\ns\nh"
}
ok: [hana-np-15.cisco.com] => {
    "msg": "B\nl\nu\ne\n \nf\ni\ns\nh"
}

How do I properly concatenate a list of strings with the newline character?

Discontinue answered 12/11, 2017 at 2:22 Comment(0)
M
97

Solution

join filter works on lists, so apply it to your list:

- name: Concatenate the public keys
  set_fact:
    my_joined_list: "{{ my_list | join('\n') }}"

Explanation

While my_list in your example is a list, when you use with_items, in each iterationitem is a string. Strings are treated as lists of characters, thus join splits them.

It’s like in any language: when you have a loop for i in (one, two, three) and refer to i inside the loop, you get only one value for each iteration, not the whole set.


Remarks

  • Don’t use debug module, but copy with content to have\n rendered as newline.

  • The way you create a list is pretty cumbersome. All you need is (quotation marks are also not necessary):

    - name: Create the list
      set_fact:
        my_list:
          - "One fish"
          - "Two fish"
          - "Red fish"
          - "Blue fish"
    
Mahican answered 12/11, 2017 at 10:6 Comment(1)
So it helps to apply the filter to the correct variable. And that's where I am on the learning curve, figuring out which is the correct variable. Once again, thanks!Discontinue
E
2

If you want to create a multiline string from a list of strings, you can use a jinja2 loop like this:

- name: Concatenate the public keys
  set_fact:
    my_joined_list: |
      {% for item in my_list %}
      {{ item }}
      {% endfor %}

- name: Examine the joined string
  debug:
    msg: "{{ my_joined_list }}"
Educationist answered 2/11, 2023 at 14:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.