Не используя библиотеку 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
Однако это не является надежным в отношении таких вещей, как «Я хочуIP-адреса, в которых нет «2», так как проверка 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])