更新字典列表中的值

问题描述 投票:0回答:2

我有以下词典列表:

"errorlist": [
    {
        "error": "Not found",
        "path": "/tmp/working/directory1/file1"
    },
    {
        "error": "Not found",
        "path": "/tmp/working/directory2/file1"
    },
    {
        "error": "Not found",
        "path": "/tmp/working/directory1/file2"
    },
    {
        "error": "Not found",
        "path": "/tmp/working/directory2/file2"
    }
]

我想删除路径值的“/tmp/working/”部分,即将绝对路径转换为相对路径。

我在网上搜索时也遇到过类似的问题,但没有找到解决方案。它应该相当简单,但我无法理解它。

预期结果应该是具有更新值的原始列表或具有相同结构的新列表。

ansible
2个回答
1
投票

过滤基本名称并创建字典列表

  paths: "{{ errorlist | map(attribute='path') | map('basename') |
                         map('community.general.dict_kv', 'path') }}"

给予

  paths:
    - {path: file1}
    - {path: file1}
    - {path: file2}
    - {path: file2}

压缩列表并合并项目

  result: "{{ errorlist | zip(paths) | map('combine') }}"

给予

  result:
    - {error: Not found, path: file1}
    - {error: Not found, path: file1}
    - {error: Not found, path: file2}
    - {error: Not found, path: file2}

根据您的需要安装管道。


  • 用于测试的完整剧本示例
- hosts: localhost

  vars:

    errorlist:
      - {error: Not found, path: /tmp/working/directory1/file1}
      - {error: Not found, path: /tmp/working/directory2/file1}
      - {error: Not found, path: /tmp/working/directory1/file2}
      - {error: Not found, path: /tmp/working/directory2/file2}

    paths: "{{ errorlist | map(attribute='path') | map('basename') |
                           map('community.general.dict_kv', 'path') }}"
    result: "{{ errorlist | zip(paths) | map('combine') }}"

  tasks:

    - debug:
        var: paths | to_yaml
    - debug:
        var: result | to_yaml
  • 根据您的需要安装过滤器。例如,要删除字符串的任何部分,请使用过滤器 regex_replace
  paths: "{{ errorlist | map(attribute='path') |
                         map('regex_replace', '/tmp/working/(.*)', '\\1') |
                         map('community.general.dict_kv', 'path') }}"

给予

  paths:
    - {path: directory1/file1}
    - {path: directory2/file1}
    - {path: directory1/file2}
    - {path: directory2/file2}

这将导致

  result:
    - {error: Not found, path: directory1/file1}
    - {error: Not found, path: directory2/file1}
    - {error: Not found, path: directory1/file2}
    - {error: Not found, path: directory2/file2}

问:“如果没有community.general.dict_kv,我怎样才能达到相同的结果?”

A:使用json_query。下面的声明给出了相同的结果

  paths: "{{ errorlist | map(attribute='path') |
                         map('regex_replace', '/tmp/working/(.*)', '\\1') |
                         json_query('[].{path: @}') }}"

在 Ansible 2.9 及更低版本中尝试添加过滤器列表

  paths: "{{ errorlist | map(attribute='path') | list |
                         map('regex_replace', '/tmp/working/(.*)', '\\1') | list |
                         json_query('[].{path: @}') | list }}"

调试

分解管道

  path1: "{{ errorlist | map(attribute='path') }}"
  path2: "{{ errorlist | map(attribute='path') |
                         map('regex_replace', '/tmp/working/(.*)', '\\1') }}"
  path3: "{{ errorlist | map(attribute='path') |
                         map('regex_replace', '/tmp/working/(.*)', '\\1') |
                         json_query('[].{path: @}') }}"

并显示中间结果类型

    - debug:
        msg: "{{ path1 | type_debug }}"
    - debug:
        msg: "{{ path2 | type_debug }}"
    - debug:
        msg: "{{ path3 | type_debug }}"

1
投票

Ansible 并不是一个很好的数据操作工具。对于您想要做的事情,最简单的解决方案可能是用 Python 编写的自定义过滤器。将以下内容放入

filter_plugins/filters.py
(其中
filter_plugins
目录与您的剧本位于同一目录中):

def replaceInAttribute(data, attr, find, replace):
    for d in data:
        if attr in d:
            d[attr] = d[attr].replace(find, replace)

    return data


class FilterModule:
    def filters(self):
        return {
            "replaceInAttribute": replaceInAttribute,
        }

现在你可以编写这样的剧本:

- hosts: localhost
  gather_facts: false
  vars:
    errorlist: [
        {
            "error": "Not found",
            "path": "/tmp/working/directory1/file1"
        },
        {
            "error": "Not found",
            "path": "/tmp/working/directory2/file1"
        },
        {
            "error": "Not found",
            "path": "/tmp/working/directory1/file2"
        },
        {
            "error": "Not found",
            "path": "/tmp/working/directory2/file2"
        }
    ]
  tasks:
  - debug:
      msg: "{{ errorlist | replaceInAttribute('path', '/tmp/working/', '') }}"

并得到这个输出:

TASK [debug] *************************************************************************************************************************************************************
ok: [localhost] => {
    "msg": [
        {
            "error": "Not found",
            "path": "directory1/file1"
        },
        {
            "error": "Not found",
            "path": "directory2/file1"
        },
        {
            "error": "Not found",
            "path": "directory1/file2"
        },
        {
            "error": "Not found",
            "path": "directory2/file2"
        }
    ]
}

此处介绍的过滤器比所需的稍微复杂一些,因为它支持任意属性的查找/替换。

© www.soinside.com 2019 - 2024. All rights reserved.