Ansible 如何从值和值列表构建字符串?

Ansible 如何从值和值列表构建字符串?,ansible,ansible-template,Ansible,Ansible Template,[第一次提问者。我想我把这个问题定位为一个可回答的问题。如果不是,欢迎温和的重定向!] 鉴于: gid: 80 ports: [80, 443] 其中端口数可能从0到多个不等 我想制作一个如下的字符串: "msg": [ [ 80, "80" ], [ 443, "80" ] ] - set_fact: rul

[第一次提问者。我想我把这个问题定位为一个可回答的问题。如果不是,欢迎温和的重定向!]

鉴于:

gid: 80
ports: [80, 443]
其中端口数可能从0到多个不等

我想制作一个如下的字符串:

    "msg": [
        [
            80,
            "80"
        ],
        [
            443,
            "80"
        ]
    ]
- set_fact:
    rules_list: "{{ rules_list|default([]) + ['gid:{}:tcp:{}'.format(gid, item)] }}"
  loop: "{{ ports }}"

- set_fact:
    rules_str_1: "{{ ','.join(rules_list) }}"

- debug:
    var: rules_str_1
gid:80:tcp:80,gid:80:tcp:443

(正好是FreeBSD mac_portacl规则字符串)

我得到的最远信息是:

portacl_rules: "{{ ports | zip_longest([], fillvalue='80') | list }}"
这给了我这样的感觉:

    "msg": [
        [
            80,
            "80"
        ],
        [
            443,
            "80"
        ]
    ]
- set_fact:
    rules_list: "{{ rules_list|default([]) + ['gid:{}:tcp:{}'.format(gid, item)] }}"
  loop: "{{ ports }}"

- set_fact:
    rules_str_1: "{{ ','.join(rules_list) }}"

- debug:
    var: rules_str_1
但是:

  • gid是硬编码的,我不知道如何插值变量值;及
  • 我无法将列表转换为最终字符串
我可以通过定义一个临时变量来创建gid字符串,
gid:80

gid: 80
_tmp_gid: "gid:{{ gid }}"
但是因为我不能在fillvalue中插入字符串,所以我被卡住了

我对
格式
过滤器进行了修改,但它似乎将输出字符串作为输入,将值作为参数,这与我的情况相反


有什么建议吗?

如果您不介意一对
set\u fact
任务,您可以这样做:

    "msg": [
        [
            80,
            "80"
        ],
        [
            443,
            "80"
        ]
    ]
- set_fact:
    rules_list: "{{ rules_list|default([]) + ['gid:{}:tcp:{}'.format(gid, item)] }}"
  loop: "{{ ports }}"

- set_fact:
    rules_str_1: "{{ ','.join(rules_list) }}"

- debug:
    var: rules_str_1
第一个任务创建表单列表:

[
  "gid:80:tcp:80",
  "gid:80:tcp:443"
]
第二个任务使用
连接这些项

您可以使用稍微复杂的表达式在单个操作中完成该操作,该表达式涉及
regex\u replace
过滤器:

- set_fact:
    rules_str_2: '{{ ",".join(ports|map("regex_replace", "^(.*)$", "gid:{}:tcp:\1".format(gid))) }}'

- debug:
    var: rules_str_2
要使该
设置\u fact
任务按编写的方式工作,必须在外部使用单引号(这禁止将
\
用作转义字符)。你可以交换引号,但是你需要写
\\
,而不是
\
。回想一下,匹配表达式中的
(…)
创建了一个捕获组,替换字符串中的
\1
扩展为第一个捕获组的值


将所有这些放在一个剧本中:

---
- hosts: localhost
  gather_facts: false
  vars:
    gid: 80
    ports: [80, 443]
  tasks:
    - set_fact:
        rules_list: "{{ rules_list|default([]) + ['gid:{}:tcp:{}'.format(gid, item)] }}"
      loop: "{{ ports }}"

    - set_fact:
        rules_str_1: "{{ ','.join(rules_list) }}"

    - debug:
        var: rules_str_1

    - set_fact:
        rules_str_2: '{{ ",".join(ports|map("regex_replace", "(.*)", "gid:{}:tcp:\1".format(gid))) }}'

    - debug:
        var: rules_str_2
这将产生以下输出:

PLAY [localhost] ******************************************************************************************************************************************************************************

TASK [set_fact] *******************************************************************************************************************************************************************************
ok: [localhost] => (item=80)
ok: [localhost] => (item=443)

TASK [set_fact] *******************************************************************************************************************************************************************************
ok: [localhost]

TASK [debug] **********************************************************************************************************************************************************************************
ok: [localhost] => {
    "rules_str_1": "gid:80:tcp:80,gid:80:tcp:443"
}

TASK [set_fact] *******************************************************************************************************************************************************************************
ok: [localhost]

TASK [debug] **********************************************************************************************************************************************************************************
ok: [localhost] => {
    "rules_str_2": "gid:80:tcp:80,gid:80:tcp:443"
}

PLAY RECAP ************************************************************************************************************************************************************************************
localhost                  : ok=5    changed=0    unreachable=0    failed=0

谢谢你的解决方案。两步回答有效,但一步不行(在我手里…),它给出了“规则”——“gid:80:tcp:80gid:80:tcp:,gid:80:tcp:443gid:80:tcp:,gid:80:tcp:987gid:80:tcp:”。我不知道如何做一个包含所有信息的更长的回复…请参阅我的评论和我的原始问题,两步版本有效,单步版本不适用于我。请尝试更新的版本(我必须锚定正则表达式,因此它现在读作
^(.*$
)。啊,我明白了。您编辑了这篇散文,但“将其全部放在剧本中”示例仍然包含旧版本(这就是我剪切和粘贴的内容)。使用锚定的regexp,效果非常好。再次感谢!!!