24

I have very simple line in the template:

ip={{ip|join(', ')}}

And I have list for ip:

ip:
 - 1.1.1.1
 - 2.2.2.2
 - 3.3.3.3

But application wants IPs with quotes (ip='1.1.1.1', '2.2.2.2').

I can do it like this:

ip:
 - "'1.1.1.1'"
 - "'2.2.2.2'"
 - "'3.3.3.3'"

But it is very ugly. Is any nice way to add quotes on each element of the list in ansible?

Thanks!

George Shuklin
  • 6,952
  • 10
  • 39
  • 80

9 Answers9

29

This will work :

ip={{ '\"' + ip|join('\", \"') + '\"' }}

A custom filter plugin will also work. In ansible.cfg uncomment filter_plugins and give it a path, where we put this

def wrap(list):
    return [ '"' + x + '"' for x in list]

class FilterModule(object):
    def filters(self):
        return {
            'wrap': wrap
        }

in a file called core.py. Like this. Then you can simply use

ip|wrap|join(', ')

And it should produce comma seperated list with each ip wrapped in quotes.

Craig Scott
  • 9,238
  • 5
  • 56
  • 85
Zasz
  • 12,330
  • 9
  • 43
  • 63
  • 1
    This works like a charm. And if you want this just for one project / playbook, simply put a `filter_plugins` folder in your project and call the file, as already mentioned, `core.py`. – incredibleholg Apr 07 '17 at 06:53
  • 2
    Shouldn't it be `ip={{ '\"' + ip|join('\", \"') + '\"'}}` ? – LoicAG Aug 01 '17 at 13:46
26

Actually there is a very simple method to achieve this:

{{ mylist | map('quote') | join(', ') }}

The filter map iterates over every item and let quote process it. Afterwards you can easily join them together.

Max
  • 904
  • 8
  • 15
13

try:

- hosts: localhost
  tags: s20
  gather_facts: no
  vars:
    ip:
      - 1.1.1.1
      - 2.2.2.2
      - 3.3.3.3
    joined_ip: "'{{ \"', '\".join(ip)}}'"
  tasks:
  - debug: msg="(ip={{joined_ip}})"

PS: ansible supports a bit of python code execution within {{}}, which is what i'm misusing here.

Kashyap
  • 15,354
  • 13
  • 64
  • 103
6

Following worked for me

('{{ iplist | join('\',\'') }}')

Ex:

Inventory

[ips]
1.1.1.1
2.2.2.2
3.3.3.3

#cat temp.sh.j2 

 "ips": (ip='{{ groups['zoo'] | join('\',\'') }}') 

result:

#cat temp.sh

 "ips": (ip='1.1.1.1','2.2.2.2','3.3.3.3')

Hope it would help someone.

f-society
  • 2,898
  • 27
  • 18
  • works good for not empty list. but for empty array, it will result with [''] – elprup Nov 19 '18 at 05:55
  • If you want tp use double quotes (it's also a bit clear for me): `("{{ iplist | join('\",\"') }}")` – Xabs Oct 05 '22 at 07:22
6

As mentioned in this blog: https://medium.com/opsops/how-enquote-list-elements-faab833e25fe

Use to_json filter. This will double quote every string of the list:

list_of_string | map("to_json")

The problem with the "quote" filter is that it does not quote elements that dont need to be quoted from a bash perspective (no space in the string). But for windows commands sometimes strings must be quoted anyway.

ninjaconcombre
  • 456
  • 4
  • 15
2

NOTE This is similar to Kashyap's answer, but i needed a slightly different version: Using it to double quote each items in a bash array), eg. result should be:

SOME_LIST=( "Johnny" "Joey" "Dee Dee" "Tommy" )

projects/ansible/expand_list.yml

---
- hosts: localhost
  connection: local

  vars:
    some_list:
      - Johnny
      - Joey
      - Dee Dee
      - Tommy

  tasks:
    - name: "Expand the ramones band members list."
      template:
        src: "templates/expand_list.conf.j2"
        dest: "/var/tmp/ramones.conf"

projects/ansible/templates/expand_list.conf.j2

SOME_LIST=( "{{ '" "'.join(some_list) }}" )
huch
  • 675
  • 8
  • 13
2

I found the simplest way to do this with an existing Ansible filter is using regex_replace.

{{ ip | map("regex_replace","(.+)","\'\\1\'") | join(',')}}
Notabee
  • 51
  • 2
1

I've developed a custom wrap filter

def wrap(value, wrapper = '"'):
  return wrapper + value + wrapper

class FilterModule(object):
  def filters(self):
    return {
      'wrap': wrap
    }

As you can see wrapper is customizable and defaults to "

You can use it this way

ip={{ ip | map('wrap') | join(', ') }}

Disclaimer: I'm a python and ansible newbie

Adriano Di Giovanni
  • 1,445
  • 1
  • 16
  • 34
1

You can use regex_replace, f.e. in a j2 template file:

(ip={{ip | map('regex_replace', '(.*)', "'\\1'") | join(',')}})

If you do this inline in a play, do not forget to escape the double quotes. Here is a full example:

- hosts: localhost
  gather_facts: no
  vars:
    ip:
    - 1.1.1.1
    - 2.2.2.2
    - 3.3.3.3
    ip_result: "{{ip | map('regex_replace', '(.*)', \"'\\1'\") | join(',')}}"
  tasks:
  - debug: msg="(ip={{ip_result}})"
  - copy: content="(ip={{ip_result}})" dest=./ip_result.txt

Content of ip_result.txt:

$ cat ip_result.txt
(ip='1.1.1.1','2.2.2.2','3.3.3.3')
Hüda
  • 399
  • 3
  • 5