我想从 Ansible 的字典中删除单个键。
例如,我想要这样:
- debug: var=dict2
vars:
dict:
a: 1
b: 2
c: 3
dict2: "{{ dict | filter_to_remove_key('a') }}"
打印此内容:
ok: [localhost] => {
"dict2": {
"b": 2,
"c": 3
}
}
请注意,字典是从 json 文件加载的,我将其发布到 Grafana REST API。我希望允许在文件中保存“id”密钥并在发布之前删除该密钥。
这更接近我移除的实际用途:
- name: Install Dashboards
uri:
url: "{{ grafana_api_url }}/dashboards/db"
method: POST
headers:
Authorization: Bearer {{ grafana_api_token }}
body:
overwrite: true
dashboard:
"{{ lookup('file', item) | from_json | removekey('id') }}"
body_format: json with_fileglob:
- "dashboards/*.json"
- "../../../dashboards/*.json"
- set_fact:
dict:
a: 1
b: 2
c: 3
dict2: {}
- set_fact:
dict2: "{{dict2 |combine({item.key: item.value})}}"
when: "{{item.key not in ['a']}}"
with_dict: "{{dict}}"
- debug: var=dict2
或者创建一个过滤器插件并使用它。
- debug: var=dict2
vars:
dict:
a: 1
b: 2
c: 3
dict2: '{{ dict | dict2items | rejectattr("key", "eq", "a") | list | items2dict }}'
#dict2: '{{ dict | dict2items | rejectattr("key", "match", "^(a|b)$") | list | items2dict }}'
输出:
ok: [localhost] => {
"dict2": {
"b": 2,
"c": 3
}
}
这是一种受 John Mazzitelli 的文章启发的方法,可以内联使用,无需额外的
set_fact
任务等:
tasks:
- debug: var=dict2
vars:
dict:
a: 1
b: 2
c: 3
# It is important that there be NO WHITESPACE outside of `{% ... %}` and `{{ ... }}`
# or else the var will be converted to a string. The copy() step optionally prevents
# modifying the original. If you don't care, then: "{% set removed=dict.pop('a') %}{{dict}}"
dict2: "{% set copy=dict.copy() %}{% set removed=copy.pop('a') %}{{ copy }}"
TASK [debug] ***********
ok: [localhost] => {
"dict2": {
"b": 2,
"c": 3
}
}
您可以使用 ansible.utils.remove_keys 过滤器。它将删除all嵌套层上的给定键。所以它可能并不适合所有场景:
- debug: var=dict2
vars:
dict:
a: 1
b: 2
c: 3
dict2: "{{ dict | ansible.utils.remove_keys(target=['a']) }}"
输出:
ok: [localhost] =>
dict2:
b: 2
c: 3
如果您想删除特定图层上的特定键,您可以像这样弹出该键:
- debug: var=dict2
vars:
dict:
a: 1
b: 2
c: 3
dict2: |
{% set a = dict.pop('a') %}
{{ dict }}
更深层次嵌套的示例:
- debug: var=dict2
vars:
dict:
sub_dict:
a: 1
b: 2
c: 3
dict2: |
{% set a = dict.sub_dict.pop('a') %}
{{ dict }}
如果您对过滤器感兴趣(我认为这是删除字典中项目的最干净的方法),则在您的剧本所在的目录中创建
filter_plugins/dicts.py
,并填充它:
'''Custom ansible filters for dicts'''
import copy
class FilterModule(object):
def filters(self):
return {
'del_by_list': self.del_by_list
}
def del_by_list(self, dict_to_reduce, list_of_keys):
'''Deletes items of dict by list of keys provided'''
dict_to_return = copy.deepcopy(dict_to_reduce)
for item in list_of_keys:
if item in dict_to_return:
del dict_to_return[item]
return dict_to_return
你可以走了:
---
- hosts: hadoop
gather_facts: no
tasks:
- debug:
msg: "{{ {123: 456, 789: 123} | del_by_list([123]) }}"
这将产生
{789: 123}
另一种可能的解决方案,不使用过滤器,仍然只删除第一层(或可控层深度)是使用 dict2items 和 items2dict
- set_fact:
temp:
a: 1
b:
c: 2
d:
- 3
- debug:
var: temp | dict2items | selectattr('key', 'ne', 'b') | items2dict
这将导致:
a: 1
d:
- 3
使用此选择属性,您还可以定义更好的检查以删除哪些键。