bash - 通过有条件地覆盖第二个文件的部分来合并两个文件

标签 bash awk sed diff

我有两个配置文件,旧的和新的。 New 是一个带有默认值和附加变量的模板配置。 Old 是修改后的配置,其中包含必须保留的值。我需要做一个新的修改配置:

  1. 如果变量在新旧版本中都存在,则保留旧值
  2. 如果变量在旧版本中被注释掉,则保持不变,反之亦然
  3. 如果变量只存在于old中,则删除它
  4. 如果变量只存在于new中,则保留

旧修改

$ cat old.cfg
# var1 = 111
# var2 = 123
var3 = 111
var4 = 123
var5 = 123

新的默认配置

$ cat new_default.cfg
var1 = 111
# var2 = 123
var3 = 111
# var4 = 111
var6 = 111

新修改的配置(期望的)

$ cat new.cfg
# var1 = 111
# var2 = 123
var3 = 111
var4 = 123
var6 = 111

# 总是用空格分隔(因为配置编辑是手动的,我为此使用 sed:sed -i -E 's/^# ([^ ])/#\1/'), 所以也许 awk 可以用于整个事情。现在我有这个 awk 'FNR==NR{a[$1]++;next}!a[$1]' new_default.cfg old.cfg 写下变量名(第一列在 awk 中),这对两个文件都是通用的。

============================================= ====

更新: 最后,我使用了下面的答案并对其进行了修改,因此它现在可以更好地满足我的需求,而且看起来更丑陋。

  1. 接受两个参数,旧配置和补丁配置的模板
  2. 确保在行首的#之后有一个空格
  3. 确保每个 = 的每一侧都被一个空格包围
  4. 确保每个实际评论都以两个 # 而不是一个开始
  5. 发出 awk 命令:如果行以 # 开头 -> 比较第二列; 以 ## 开头 -> 比较整行;开始时没有 # -> 先比较 专栏

.

#!/bin/bash
for var in "$@"
do
    cp $var $var.bak
    sed -i -E 's/^#([^ ])/# \1/' $var
    sed -i -E 's/(.?)(\s?)=(\s?)(.?)/\1 = \4/' $var
    sed -i -E 's/^#([^=]+)$/##\1/' $var
done
awk '{if(/^# /)k=$2;else if(/^## /)k=$0;else k=$1;}NR==FNR{a[k]=$0; next} 
{print (k in a)?a[k]:$0}' $1 $2 > output.txt

最佳答案

awk 助您一臂之力!

$ awk       '{k=/^#/?$2:$1} 
     NR==FNR {a[k]=$0; next}
             {print (k in a)?a[k]:$0}' config.old config.new

# var1 = 111
# var2 = 123
var3 = 111
var4 = 123
var6 = 111

虽然不确定所有测试都包含在您的示例输入/输出中。

关于bash - 通过有条件地覆盖第二个文件的部分来合并两个文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50724942/

相关文章:

r - 从 R 调用 sed 时转义引号

linux - 有什么办法可以在模式匹配后在 sed 中增加一些数字

linux - 用sed在标点符号后面加空格

linux - 无法在 Linux 上删除目录 ${env.DELETED_ITEMS}

bash - 在不生成子 shell 的情况下使用 bash 运行多个命令

linux - Qt 创建者进程 ID 更改

bash - 如何使用 awk 按天将带时间戳的日志文件拆分为多个文件

csv - 将 block 中的行转换为制表符分隔

bash - Bash 中的命令行参数

regex - 从文本文件中的重复范围模式中获取特定行