Regex 使用sed进行模式匹配后的多行模式

Regex 使用sed进行模式匹配后的多行模式,regex,bash,unix,sed,Regex,Bash,Unix,Sed,我有一个由多个部分组成的配置文件,其中许多部分包含一个同名的属性,让它成为host。我只需要替换一个特定节的host属性。以下是文件: section1 { ... setting1 = "true" ... host = "localhost" ... } section2 { ... host = "whatever" ... } 我想用其他内容替换section2的host值。请注意,中间可能有任意数量的行,标记为… sed -i.bak '/^secti

我有一个由多个部分组成的配置文件,其中许多部分包含一个同名的属性,让它成为
host
。我只需要替换一个特定节的
host
属性。以下是文件:

section1 {
  ...
  setting1 = "true"
  ...
  host = "localhost"
  ...
}
section2 {
  ...
  host = "whatever"
  ...
}
我想用其他内容替换
section2
host
值。请注意,中间可能有任意数量的行,标记为

sed -i.bak '/^section2 {/,/^}/s/host .*/host = "newvalue"/' file
这将在
部分2{
和下一个
}
之间进行搜索,更改所有
主机=
事件。GNU sed语法,您应该在OSX上使用eg
sed-i'.


这将在
部分2{
和下一个
}
之间进行搜索,更改所有
主机=
事件。GNU sed语法,您应该在OSX上使用例如
sed-i'.

awk
来拯救它

$ awk 'BEGIN{RS=ORS="\n}"}
  /section2/{sub("host =[^\n]*", "host = \"newvalue\"")}NF' file 

section1 {
  ...
  setting1 = "true"
  ...
  host = "localhost"
  ...
}
section2 {
  ...
  host = "newvalue"
  ...
}

定义记录结构,找到相应的记录并替换。

awk
救援

$ awk 'BEGIN{RS=ORS="\n}"}
  /section2/{sub("host =[^\n]*", "host = \"newvalue\"")}NF' file 

section1 {
  ...
  setting1 = "true"
  ...
  host = "localhost"
  ...
}
section2 {
  ...
  host = "newvalue"
  ...
}
定义记录结构,找到相应的记录并替换。

可能是最佳选择

要用
awk
解决方案(一种经过校正的、更健壮的版本)对其进行补充:

  • 使用GNU
    awk
    :谢谢
  • 使用
    mawk
    (不太健壮;也可以使用GNU
    awk
    ):
注意:由于使用多字符
RS
值,两种解决方案均不适用于BSD/OSX
awk
;要让它在那里发挥作用需要付出更多的努力

说明:

  • RS=ORS=“}\n”
    告诉
    awk
    }\n
    实例将输入拆分为记录(通过特殊变量
    RS
    ,输入记录分隔符),并对输出使用相同的分隔符(通过
    ORS
    ,输出记录分隔符)

  • /^section2/
    在每条记录的开头匹配literal
    section

    • Mawk解决方案:
      {sub(/host=[^\n]*/,“host=\“new value\”)}
      用新值替换key
      host
      的值

      • 请注意,只需要匹配下一个换行符
        ([^\n]*)
        ,因为只要
        *
        就可以跨换行符匹配到记录的末尾
      • 最好更可靠地匹配
        主机
        键,例如使用
        sub(“/(\n*host=)…
        ),但您需要捕获组引用以在替换值中保留相同数量的前面空白,而
        sub()
        不支持该值。
        然而,GNU
        awk
        确实通过其非标准的
        gensub()
        函数提供捕获组引用;请参见下文
    • GNU Awk解决方案:使用非标准的
      gensub()
      函数可以使用捕获组(
      \\1
      表示第一个捕获组,…),这使得替换更加健壮和方便

      • gensub()
        ,不同于
        sub()
        ,gensub()不修改输入字符串,而是返回修改后的副本-因此需要将其分配给
        $0
      • 1
        第三个参数告诉
        gensub()
        仅替换1个匹配项
  • 1
    是一种常用的速记,用于简单地打印生成的记录

    • 可能是最好的选择

      要用
      awk
      解决方案(一种经过校正的、更健壮的版本)对其进行补充:

      • 使用GNU
        awk
        :谢谢
      • 使用
        mawk
        (不太健壮;也可以使用GNU
        awk
        ):
      注意:由于使用多字符
      RS
      值,这两种解决方案都不适用于BSD/OSX
      awk
      ;在那里工作需要更多的努力

      说明:

      • RS=ORS=“}\n”
        告诉
        awk
        }\n
        实例将输入拆分为记录(通过特殊变量
        RS
        ,输入记录分隔符),并对输出使用相同的分隔符(通过
        ORS
        ,输出记录分隔符)

      • /^section2/
        在每条记录的开头匹配literal
        section

        • Mawk解决方案:
          {sub(/host=[^\n]*/,“host=\“new value\”)}
          用新值替换key
          host
          的值

          • 请注意,只需要匹配下一个换行符
            ([^\n]*)
            ,因为只要
            *
            就可以跨换行符匹配到记录的末尾
          • 最好更可靠地匹配
            主机
            键,例如使用
            sub(“/(\n*host=)…
            ),但您需要捕获组引用以在替换值中保留相同数量的前面空白,而
            sub()
            不支持该值。
            然而,GNU
            awk
            确实通过其非标准的
            gensub()
            函数提供捕获组引用;见下文
        • GNU Awk解决方案:使用非标准的
          gensub()
          函数可以使用捕获组(
          \\1
          表示第一个捕获组,…),这使得替换更加健壮和方便

          • gensub()
            ,不同于
            sub()
            ,gensub()不修改输入字符串,而是返回修改后的副本-因此需要将其分配给
            $0
          • 1
            第三个参数告诉
            gensub()
            仅替换1个匹配项
      • 1
        是一种常用的速记,用于简单地打印生成的记录


      我还必须添加
      -I
      ,但是是的,这非常有效。非常感谢。我还必须添加
      -I
      ,但是是的,这非常有效。非常感谢。很有希望,但是(a)它打印了一个额外的
      awk '
        BEGIN{ RS=ORS="}\n" }
        /^section2/ { sub(/ host = [^\n]*/, " host = \"new value\"") }
        1' file