如何制作和应用(修补)一侧差异?

如何制作和应用(修补)一侧差异?

我想制作一个更新配置文件的 shell 脚本。

服务器上存在的文件包含信息,例如各种 IP 地址。

新文件有更多代码,来自添加到系统的新配置,我希望能够将这些新配置添加到服务器文件,而不更改那里已经配置的内容

例子:

服务器文件

[config]
ip=127.0.0.1
port=22

新文件

[config]
ip=XXX.XXX.XXX.XXX
port=XX
user=root

我希望生成的文件是

[config]
ip=127.0.0.1
port=22
user=root

怎样才是一个好方法呢?我不想依赖行位置等,因为实际的配置文件非常大,可以将更多行添加到服务器文件中。

我尝试对文件进行比较并应用补丁,但没有成功。

谢谢你的帮助。

答案1

正如吉尔斯所说,您需要使用一个了解配置文件格式的工具。对于您的特定示例,您可以使用一个简短的 Python 脚本,该脚本使用内置的配置解析器模块。

  • 首先,假设服务器上的原始配置文件是original.cfg

    [config]
    ip=127.0.0.1
    port=22
    
  • 现在将您的更改放入一个名为的新文件中update.cfg

    [config]
    user=root
    

    该文件应该在您希望它们所在的部分标题下列出新的或更改的条目。

  • 然后运行如下脚本:

    #!/usr/bin/env python
    
    import ConfigParser
    
    config = ConfigParser.ConfigParser()
    
    # Read the original config file
    with open('original.cfg', 'r') as f:
        config.readfp(f)
    
    # Also read in all the changes we'd like to make
    with open('update.cfg', 'r') as f:
        config.readfp(f)
    
    # Write the full new config file out
    with open('output.cfg', 'w') as f:
        config.write(f)
    

当然,如何做到这一点有很多变化。例如,配置更改可以直接编码到 Python 脚本中,而不是从单独的update.cfg文件中读取。不过,这应该为您提供良好的入门基础。

答案2

使用您喜欢的任何程序将它们解析为两个单独的数据集。我将使用 common lisp 并将每个配置文件存储为列表的嵌套列表。

然后使用语言工具进行合并/修补/联合/设置差异等。从较高的层次来看,对于一侧差异,代码可能如下所示:

(union
  (vals A :keys 'all)
  (vals B
    :keys  
    (set-difference
      (keys B)
      (keys A))))

然后将生成的数据集写入文件。

答案3

我用配置对象用于此目的的 Python 库。如果这样做,确实需要编写 Python 来与配置文件交互。我通常有一个default_conf具有默认值的文件,并且我可以有选择地用其他一些文件覆盖这些设置,例如user_conf

这是我当前用作示例的代码。函数的后半部分是验证,这很重要,但您可以忽略它以进行第一个近似。对于您所做的使用

conf = get_conf()
ip = conf["ip"]

在您的情况下,我猜想服务器文件是覆盖的文件,尽管更常见的是用户文件覆盖系统文件。这当然是 Unix 类型系统中的用户约定。

要将 ConfigObj 对象写入文件,您要做的第一个近似(如果config是您的对象,如下面的脚本所示)

config.filename = filename
config.write()

因此,如果需要,您可以修改下面的函数以写入文件,而不是返回配置对象。看编写配置文件了解更多细节。

def get_conf():
    import configobj, validate, sys
    try:
        config = configobj.ConfigObj('default_conf', configspec='conf.validate', raise_errors=True)
    except configobj.ConfigObjError:
        print "ERROR FOR CONFIG FILE 'default_conf':"
        raise
    try:
        user = configobj.ConfigObj('user_conf', configspec='conf.validate', raise_errors=True)
    except configobj.ConfigObjError:
        print "ERROR FOR CONFIG FILE 'user_conf':"
        raise
    config.merge(user)

    #This is config file validation
    fdict = {'check_list_of_list_of_integers': list_of_list_of_integers}
    validator = validate.Validator(fdict)

    results = config.validate(validator, preserve_errors=True)
    if results != True:
        for entry in configobj.flatten_errors(config, results):
            # each entry is a tuple
            section_list, key, error = entry
            if key is not None:
                section_list.append(key)
            else:
                section_list.append('[missing section]')
            section_string = ', '.join(section_list)
            if error == False:
                error = 'Missing value or section.'
            print section_string, ' = ', error

        sys.exit(1)

    return config

2015 年 12 月 16 日更新:像 YAML 这样的东西可能是更好的通用解决方案。我建议用它来代替 ConfigObj。一方面,它更加灵活。

相关内容