使用 Python 更改 YAML 中的特定变量

Changing specific variable in YAML with Python

我有一个用于 Ansible 的 YAML 变量文件。 我正在尝试构建一个 python 脚本来更改 YAML 文件中的特定变量。

YAML 文件 accsw01.yml 看起来像这样:

interface_vars:
- {interface: Ethernet1/1, description: Test_interface_1, access_vlan: 10}
- {interface: Ethernet1/2, description: Test_interface_2, access_vlan: 20}

我使用 while 循环在 YAML 文件中找到正确的接口变量:

interface = input("Enter interface: ")
yaml_file_printout = pprint.PrettyPrinter(indent=2)
with open("/ansible/inventories/test/host_vars/accsw01.yml", "r") as yaml_file:
    yaml_read = yaml.load(yaml_file, Loader=yaml.FullLoader)
    interface_count = 0
    while True:
        output_interface = yaml_read["interface_vars"][interface_count]["interface"]
        if interface != output_interface:
            interface_count += 1
        elif interface == output_interface:
            yaml_file_printout.pprint(yaml_read["interface_vars"][interface_count])
            break

如何让 python 更改界面 Ethernet1/2 上的 access_vlan,同时保持文件的其余部分完好无损?

我试过:

使用 PyYAML 附加文件,但这只是将新变量块粘贴在 YAML 文件之上..

使用 ruamel.yaml 更改变量,但虽然它更改了变量,但它从 YAML 文件中删除了所有格式并且不将变量显示为字典

首先你不能正常追加到 YAML 文件,你必须将文件读入数据结构,更改(追加,删除)数据结构,然后再转储它。

其次,你不应该在你去做的时候让文件不必要地打开 其他事情。在执行 yaml.load() 之后(无论是在 ruamel.yaml 还是在 PyYAML) 数据被读取,所以你应该退出 with 语句,通过减少你的代码

您的程序不会将读取的数据更改为 yaml_read,因此我尝试了一些明确的更改:

import sys
import pprint
import ruamel.yaml

yaml = ruamel.yaml.YAML()
# yaml.indent(mapping=4, sequence=4, offset=2)
yaml.preserve_quotes = True
yaml.default_flow_style=None

interface = 'Ethernet1/1'
yaml_file_printout = pprint.PrettyPrinter(indent=2)
with open("interface.yaml", "r") as yaml_file:
    data = yaml.load(yaml_file)  
interface_count = 0
while True:
    output_interface = data["interface_vars"][interface_count]["interface"]
    if interface != output_interface:
        interface_count += 1
    elif interface == output_interface:
        yaml_file_printout.pprint(data["interface_vars"][interface_count])
        break

print('------')
yaml.dump(data, sys.stdout)
print('------')
data['interface_vars'][1]['access_vlan'] = 30
data['interface_vars'].append(dict(interface='Ethernet1/3', description='Test_interface_3', access_vlan='5'))
yaml.dump(data, sys.stdout)

给出:

{ 'access_vlan': 10,
  'description': 'Test_interface_1',
  'interface': 'Ethernet1/1'}
------
interface_vars:
- {interface: Ethernet1/1, description: Test_interface_1, access_vlan: 10}
- {interface: Ethernet1/2, description: Test_interface_2, access_vlan: 20}
------
interface_vars:
- {interface: Ethernet1/1, description: Test_interface_1, access_vlan: 10}
- {interface: Ethernet1/2, description: Test_interface_2, access_vlan: 30}
- {interface: Ethernet1/3, description: Test_interface_3, access_vlan: '5'}

而不是全局地使叶节点成为流式(使用 yaml.default_flow_style = None) 你也可以包装字典 附加在 ruamel.yaml.comments.CommentedMap() 类型中以获得更好的 控制数据的转储方式(有一些关于如何转储的细节 这样做 )

另请注意官方推荐的 扩展 YAML 文件的 .yaml 已经超过 13 年了。