Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/bash/15.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Bash 通过有条件地覆盖第二个文件的部分来合并两个文件_Bash_Awk_Sed_Diff - Fatal编程技术网

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

Bash 通过有条件地覆盖第二个文件的部分来合并两个文件,bash,awk,sed,diff,Bash,Awk,Sed,Diff,我有两个配置文件,旧的和新的。新的是一个模板配置,带有默认值,可能还有其他变量。旧配置被修改,其值必须保留。我需要做一个新的修改配置: 若旧版本和新版本中都存在变量,则保留旧值 若变量在old中被注释掉,那个么将其保留,反之亦然 如果变量仅存在于旧版本中,请将其删除 若变量只存在于new中,则保留它 旧改性 $ cat old.cfg # var1 = 111 # var2 = 123 var3 = 111 var4 = 123 var5 = 123 新的默认配置 $ cat new_defa

我有两个配置文件,旧的和新的。新的是一个模板配置,带有默认值,可能还有其他变量。旧配置被修改,其值必须保留。我需要做一个新的修改配置:

  • 若旧版本和新版本中都存在变量,则保留旧值
  • 若变量在old中被注释掉,那个么将其保留,反之亦然
  • 如果变量仅存在于旧版本中,请将其删除
  • 若变量只存在于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
    
    新修改的配置(需要)

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

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

    UPD: 最后,我使用了下面的答案,并对其进行了修改,使其更好地满足了我的需求,而且看起来更丑

  • 接受两个参数,旧配置和修补配置的模板
  • 确保行首的
    #
    后面有空格
  • 确保每一个
    =
    每侧都有一个空间
  • 确保每个实际注释都从两个
    #
    开始,而不是一个
  • 发出awk命令:如果行以
    #
    ->开头,则比较第二列; 从
    ##
    ->开始比较整行;开始时不使用
    #
    ->先比较 纵队

  • 如果您想实现与特定于应用程序的逻辑的合并,那么获得所需逻辑的唯一可靠方法就是亲自构建它。因此:

    #!/usr/bin/env bash
    case $BASH_VERSION in ''|[123].*) echo "ERROR: Bash 4.0 or newer required" >&2; exit 1;; esac
    
    declare -A old new
    
    read_to_array() {
      local line
      local -n dest=$1
      local -n comment_dest=$2
      declare -g -A "$1" "$2"
      while IFS= read -r line; do
        case $line in
          "")          continue;;
          "#"*" = "*)  line=${line#"#"};
                       comment_dest[${line%%" = "*}]=$line;;
          "#"*)        continue;;
          *" = "*)     dest[${line%%" = "*}]=${line#*" = "};;
          *)           echo "Ignoring unrecognized line: $line" >&2
        esac
      done
    }
    
    read_to_array old old_comments <old.txt
    read_to_array new new_comments <new.txt
    declare -A done=( )
    
    for key in "${!new[@]}"; do
      # if commented out in old, leave it that way
      if [[ ${old_comments[$key]} ]]; then
        echo "#$key = ${new[$key]}"
        continue
      fi
      # key exists in both old and new; use old
      if [[ ${old[$key]} ]]; then
        echo "$key = ${old[$key]}"
        continue
      fi
      # key is only in new; keep it
      echo "$key = ${new[$key]}"
    done
    
    for key in "${!new_comments[@]}"; do
      # if present at all in old, we were already emitted
      [[ ${old[$key]} ]] && continue
      echo "${new_comments[$key]}"
    done
    
    #/usr/bin/env bash
    “|[123].*)echo”中的case$BASH_版本错误:需要BASH 4.0或更高版本“>&2;出口1;;以撒
    宣布-旧的新的
    读取到数组(){
    本地线路
    本地-n目的地=1美元
    本地-n注释目的地=$2
    声明-g-A“$1”“$2”
    当IFS=读取-r行时;执行
    案例$line in
    “”继续;;
    “#”*“=”*)行=${line#“#”};
    注释_dest[${line%%”=“*}]=$line;;
    “#”*)继续;;
    *“=”*)dest[${line%%”=“*}]=${line#*”=“};”;;
    *)echo“忽略未识别的行:$line”>&2
    以撒
    完成
    }
    
    请阅读“对数组的旧注释”
    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
    

    但是,不确定示例输入/输出中是否包含所有测试。

    此答案假设您在
    #
    =
    之间始终有空格,例如在示例输入中:

    awk '
        NR == FNR {if ($1 == "#") new_ignore[$2]; else new[$1] = $3; next }
        $1 == "#" { delete new[$2]; print; next }
        { old[$1] }
        $1 in new || $1 in new_ignore { print; next }
        END { for (key in new) if (!(key in old)) printf "%s = %s\n", key, new[key] }
    ' new_default.cfg old.cfg
    

    如果这是重复的或者我没有说清楚,我也会事先道歉。多年来一直以只读模式出现在网站上,但今天却完全被sed、awk、diff、patch等搞糊涂了(:哇,伙计们,你们太棒了!这绝对是你们所有人的精彩输入,非常感谢!
    $ 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
    
    awk '
        NR == FNR {if ($1 == "#") new_ignore[$2]; else new[$1] = $3; next }
        $1 == "#" { delete new[$2]; print; next }
        { old[$1] }
        $1 in new || $1 in new_ignore { print; next }
        END { for (key in new) if (!(key in old)) printf "%s = %s\n", key, new[key] }
    ' new_default.cfg old.cfg
    
    # var1 = 111
    # var2 = 123
    var3 = 111
    var4 = 123
    var6 = 111