python - 删除 yaml 文件中的元素
问题描述
我的 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 文件。
解决方案
如果不使用该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])
推荐阅读
- azure-devops - 具有条件手动批准作业的 DevOps 模板
- webpack - 将 webpack 块图导出到 json
- java - 为什么它说我缺少括号?
- php - 尝试使用 PHP 和 SQL 为我的游戏制作 hiscore 排行榜
- javascript - 如果用户在聊天室中,则突出显示 ping,Javascript
- php - ¿ 我可以在 Mysql 中设置同时使用两个不同的数据库吗?
- java - 为什么我的图片没有被添加?JavaSwing
- mpi - Slurm MPI 错误:ORTE 守护程序失败
- python - 如何在 GPU 上处理字符串操作?
- progressive-web-apps - 新的更新可用消息和发布操作