在字典列表中打印键的特定值

时间:2019-04-24 12:48:09

标签: ansible

我有这样的输入

ok: [localhost] => {
    "static_plugin_versions": [
        {
            "name": "ace-editor",
            "version": "1.1"
        },
        {
            "name": "analysis-core",
            "version": "1.95"
        },
        {
            "name": "ant",
            "version": "1.9"
        },
        {
            "name": "antisamy-markup-formatter",
            "version": "1.5"
        },
        {
            "name": "apache-httpcomponents-client-4-api",
            "version": "4.5.5-3.0"
        }
    ]
}

我的目标是通过指定特定名称来打印出version。在这种情况下,专门寻找version的{​​{1}}

我尝试过的是以下

analysis-core

唯一可行的是

- debug:
    var: static_plugin_versions['analysis-core']['version']

- debug:
    var: static_plugin_versions['analysis-core'].version

- debug:
    var: static_plugin_versions[analysis-core.version]

但这是不可行的,因为如果将更多条目添加到字典中,它将损坏。

任何迹象表明我在这里做错了什么。我正在寻找一种不依赖循环的方式。

编辑

试过这个

- debug:
    var: static_plugin_versions[1].version

但是我得到了

- set_fact: 
    analysis_core_version: "{{ item.version }}"
  when: "'analysis-core' in item.name"
  with_items: "{{ static_plugin_versions }}"

- debug:
    var: analysis-core-version

2 个答案:

答案 0 :(得分:1)

最简单的方法是使用selectattr过滤器,该过滤器使您可以将过滤器应用于对象列表。例如,如果我有这本剧本:

---
- hosts: localhost
  gather_facts: false
  vars:
    "static_plugin_versions": [
      {
        "name": "ace-editor",
        "version": "1.1"
      },
      {
        "name": "analysis-core",
        "version": "1.95"
      },
      {
        "name": "ant",
        "version": "1.9"
      },
      {
        "name": "antisamy-markup-formatter",
        "version": "1.5"
      },
      {
        "name": "apache-httpcomponents-client-4-api",
        "version": "4.5.5-3.0"
      }
    ]
  tasks:
    - debug:
        msg: "version of {{ item }} is {{ (static_plugin_versions|selectattr('name', 'eq', item)|first).version }}"
      loop:
        - ace-editor

输出将是:

TASK [debug] **********************************************************************************************************************************************************************************
ok: [localhost] => (item=ace-editor) => {
    "msg": "version of ace-editor is 1.1"
}

或者,使用您的示例:

- set_fact: 
    analysis_core_version: "{{ (static_plugin_versions|selectattr('name', 'eq', 'analysis-core')|first).version }}"

- debug:
    var: analysis-core-version

哪个会产生:

ok: [localhost] => {
    "analysis_core_version": "1.95"
}

如有必要,json_query过滤器允许进行更复杂的查询。

答案 1 :(得分:0)

解决方案1(未优化)

如Illias评论所建议的那样,您可以使用循环来遍历列表中的每个其他元素,匹配其name的值,并在满足条件时打印其version

- name: print version of analysis-core
  debug:
    msg: "{{ item.version }}"
  when: item.name == 'analysis-core'
  loop: "{{ static_plugin_versions }}"

与此同时,每当没有匹配项时,它将移至其他每个元素并跳过任务。如果您有成百上千个插件,那么您的ansible执行日志中将很快变得难以理解。

解决方案2(我的首选)

查询数据结构以获取所需的信息。您的朋友是json_query filter(如果您想走得更远,则应该阅读jmespath doc)。对于您的特定示例

- name: print version of analysis-core
  debug:
    msg: >-
      {{ (static_plugin_versions | json_query("[?name == 'analysis-core'].version")).0 }}

注释

  1. 我推断出您的插件名称在列表中唯一。因此,查询特定的插件名称将返回一个元素,我可以将列表中的第一个作为预期结果打印出来。
  2. 在上面的示例中,单引号和双引号的顺序很重要(请参阅jmespath specification:如果将它们切换为空白,则会得到空字符串结果。
  3. 在我的示例中,我使用了yaml折叠块,因此不必转义双引号(因为我是个非常懒惰的B @ sT @ rD:D),但是您可以使用普通字符串并转义双精度如果需要,可以引号。