是否可以使用 Ansible / Jinja2 中的格式化字符串将列表/字典列表转换为字符串列表?
我知道我可以做类似的事情:
{{["First: %d", "Second: %d"] | map("format", 1) | join(", ") }}
要得到First: 1, Second 1。
是否可以做类似的事情
{{[[1, 1], [2, 2]] | map("format", "Num %d, %d") | join(", ") }}
并导致Num 1, 1, Num 2, 2?
    - debug:
        msg: "{{ ['v1 %s', 'v2 %s']|map('format', 'XYZ')|list }}"
给出
msg:
  - v1 XYZ
  - v2 XYZ
_list: [[1, 1], [2, 2]]
下面的表达式
result: "{{ _list|
            map('join', ',')|
            map('regex_replace', _regex, _replace)|
            join(', ') }}"
_regex: '^(.*),(.*)$'
_replace: 'Num \1, \2'
给出
result: Num 1, 1, Num 2, 2
result: "{{ ['Num']|
            product(_list|map('join', ', '))|
            map('join', ' ')|
            join(', ') }}"
result: |-
  {% for i in _list %}
  Num {{ i|join(', ') }}{% if not loop.last %}, {% endif %}
  {%- endfor %}
用于测试的完整剧本示例
- hosts: localhost
  vars:
    _list: [[1, 1], [2, 2]]
    result1: "{{ ['Num']|
                product(_list|map('join', ', '))|
                map('join', ' ')|
                join(', ') }}"
    result2: "{{ _list|
                 map('join', ',')|
                 map('regex_replace', _regex, _replace)|
                 join(', ') }}"
    _regex: '^(.*),(.*)$'
    _replace: 'Num \1, \2'
    result3: |-
      {% for i in _list %}
      Num {{ i|join(', ') }}{% if not loop.last %}, {% endif %}
      {%- endfor %}
  tasks:
    - debug:
        msg: "{{ ['v1 %s', 'v2 %s']|map('format', 'XYZ')|list }}"
    - debug:
        var: result1
    - debug:
        var: result2
    - debug:
        var: result3
    - assert:
        that:
          - result1 == 'Num 1, 1, Num 2, 2'
          - result2 == 'Num 1, 1, Num 2, 2'
          - result3 == 'Num 1, 1, Num 2, 2'
对于核心format过滤器来说这是不可能的。但如果你愿意写几行Python,你可以使用自定义过滤器轻松解决这个问题。我选择了最简单的演示,您可能必须强化代码并修复边缘情况才能在现实生活中使用。您可能想查看插件开发文档以获取更多信息。
对于本示例,我将把自定义文件保存在filter_plugins与我的测试 playbook 相邻的目录中。如果您想在不同的项目之间共享,您可以将其保存在集合或角色中。
在filter_plugins/my_format_filters.py
\ndef reverse_format(param_list, format_string):\n    """format format_sting using elements in param_list"""\n    return format_string % tuple(param_list)\n\n\nclass FilterModule(object):\n    """my format filters."""\n\n    def filters(self):\n        """Return the filter list."""\n        return {\n            \'reverse_format\': reverse_format\n        }\n然后是以下示例剧本:
\n---\n- name: custom filter demo\n  hosts: localhost\n  gather_facts: false\n\n  tasks:\n    - name: map custom reverse_format filter\n      debug:\n        msg: \'{{ item.replacements | map("reverse_format", item.format) | join(", ") }}\'\n      loop:\n        - replacements:\n            - [1, 1]\n            - [2, 2]\n          format: "Num %d, %d"\n        - replacements:\n            - [\'Jack\', \'John\', 12]\n            - [\'Mary\', \'Alicia\', 34]\n          format: "%s owes %s %d\xe2\x82\xac"\n给出:
\nPLAY [custom filter demo] **************************************************************************************************************************************************************************************************************\n\nTASK [map custom reverse_format filter] ************************************************************************************************************************************************************************************************\nok: [localhost] => (item={\'replacements\': [[1, 1], [2, 2]], \'format\': \'Num %d, %d\'}) => {\n    "msg": "Num 1, 1, Num 2, 2"\n}\nok: [localhost] => (item={\'replacements\': [[\'Jack\', \'John\', 12], [\'Mary\', \'Alicia\', 34]], \'format\': \'%s owes %s %d\xe2\x82\xac\'}) => {\n    "msg": "Jack owes John 12\xe2\x82\xac, Mary owes Alicia 34\xe2\x82\xac"\n}\n\nPLAY RECAP *****************************************************************************************************************************************************************************************************************************\nlocalhost                  : ok=1    changed=0    unreachable=0    failed=0    skipped=0    rescued=0    ignored=0\n| 归档时间: | 
 | 
| 查看次数: | 3084 次 | 
| 最近记录: |