我的Yaml文件的结构如下:
---
- hostname: core-fw-tor
ip: 1.1.1.1
os: ios
password: password
platform: cisco
type: ios
username: admin
- hostname: core-rt-tor
ip: 2.2.2.2
os: ios
password: password
platform: cisco
type: ios
username: admin
- hostname: core-sw-tor
ip: 3.3.3.3
os: ios
password: password
platform: cisco
type: ios
username: admin
如何从此列表中删除/删除元素?例如,用户想要删除主机名“ core-sw-tor”的元素并更新yaml文件。
答案 0 :(得分:1)
不使用yaml
库,您可以执行以下操作:
import re
# read the yaml file like you would any other
with open('somefile.yaml') as fh:
content = fh.read()
# the - is your delimiter in yaml, with spaces surrounding it
recs = [x for x in re.split('\s-\s', content)]
recs
# ['---', 'hostname: core-fw-tor\n ip: 1.1.1.1\n os: ios\n password: password\n platform: cisco\n type: ios\n username: admin', 'hostname: core-rt-tor\n ip: 2.2.2.2\n os: ios\n password: password\n platform: cisco\n type: ios\n username: admin', 'hostname: core-sw-tor\n ip: 3.3.3.3\n os: ios\n password: password\n platform: cisco\n type: ios\n username: admin']
# To get everything *except* that entry
kept = [r for r in recs if 'core-sw-tor' not in r]
# ['---', 'hostname: core-fw-tor\n ip: 1.1.1.1\n os: ios\n password: password\n platform: cisco\n type: ios\n username: admin', 'hostname: core-rt-tor\n ip: 2.2.2.2\n os: ios\n password: password\n platform: cisco\n type: ios\n username: admin']
# Write to a new file by joining back all of the records
with open('newyaml.yaml', 'w') as fh:
fh.write('\n- '.join(kept))
将会输出
---
- hostname: core-fw-tor
ip: 1.1.1.1
os: ios
password: password
platform: cisco
type: ios
username: admin
- hostname: core-rt-tor
ip: 2.2.2.2
os: ios
password: password
platform: cisco
type: ios
username: admin
但是,这对于诸如“我想要不带'2'的ip地址”之类的东西并不太可靠,因为选中字符串内容中的2
可能会删除更多内容。将所有内容放入字典可能是更好的方法
# Starting from recs on the previous snippet
# you don't want ---, so we can just remove it with unpacking
top, *recs = recs
# I'm going to do this in a traditional for loop for visibility's sake
# use a set for fast membership tests on larger files
entries = set()
for i,rec in enumerate(recs):
# collect entry into a dictionary
d = {k.strip(): v.strip() for k,v in [x.split(':') for x in rec.split('\n')]}
# {'hostname': 'core-sw-tor', 'ip': '3.3.3.3', 'os': 'ios', 'password': 'password', 'platform': 'cisco', 'type': 'ios', 'username': 'admin'}
# as an example
# You can change the key and value here
if d.get('hostname') != 'core-sw-tor':
entries.add(i)
kept = [x for i, x in enumerate(recs) if in entries]
with open('new_yaml.yaml', 'w') as fh:
total_rec = [top, *kept]
fh.write('\n- '.join(total_rec))
输出相同并且更健壮
作为一个完整的功能,您可能会实际使用
import re
def read_yaml(path, header=True):
with open(path) as fh:
content = fh.read()
if header:
top, *s = re.split('\s-\s', content)
else:
top, s = '', re.split('\s-\s', content)
return top, s
# find by key and value, not_match implies find everything that
# *isn't* some value
def find_entries(records, key, val, not_match=True):
entries = set()
for i, rec in enumerate(records):
d = {k.strip(): v.strip() for k,v in [x.split(':') for x in rec.split('\n')]}
if not_match is True:
if d.get(key) != val:
entries.add(i)
else:
if d.get(key) == val:
entries.add(i)
return entries
## Now it's just like before
top, recs = read_yaml('someyaml.yaml')
# Now you can change this to be 'ip' and '2.2.2.2', if you wanted
ents = find_entries(recs, 'hostname', 'core-sw-tor')
kept = [x for x in recs if i in ents]
with open('newyaml', 'w') as fh:
fh.write('\n- '.join([top, *kept])
答案 1 :(得分:1)
在迭代时更改数据结构时,Python不喜欢它,因此在加载数据结构后,您必须先通过以确定要删除的项目,然后再进行一次删除它们。为了不打乱索引,从头到尾进行了删除。
假设您的示例在input.yaml
中
import sys
from pathlib import Path
import ruamel.yaml
yaml_file = Path('input.yaml')
yaml = ruamel.yaml.YAML()
yaml.preserve_quotes = True
yaml.explicit_start = True
data = yaml.load(yaml_file)
to_remove = []
for idx, item in enumerate(data):
if item['hostname'] == 'core-sw-tor':
to_remove.insert(0, idx) # creates a reversed list
for idx in to_remove:
del data[idx]
yaml.dump(data, yaml_file)
给出input.yaml
的结果:
---
- hostname: core-fw-tor
ip: 1.1.1.1
os: ios
password: password
platform: cisco
type: ios
username: admin
- hostname: core-rt-tor
ip: 2.2.2.2
os: ios
password: password
platform: cisco
type: ios
username: admin
将保留注释,带引号的标量,特殊的整数样式(十六进制,八进制,二进制),achors /别名,合并映射之类的内容。