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

时间:2016-02-26 16:46:48

标签: regex bash unix sed

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

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

我想用其他内容替换host的{​​{1}}值。请注意,中间可能有任意数量的行,标记为section2

3 个答案:

答案 0 :(得分:2)

sed -i.bak '/^section2 {/,/^}/s/host .*/host = "newvalue"/' file

这将在section2 {和下一个}之间进行搜索,从而更改所有host =次出现。 GNU sed语法,您应该在OSX上使用例如sed -i '' ...

答案 1 :(得分:1)

awk救援!

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

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

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

答案 2 :(得分:0)

Joao Morais's answer可能是最好的选择。

使用awk解决方案(更正,更强大的karakfa's answer版本)来补充它:

awk '
  BEGIN{ RS=ORS="}\n" }
  /^section2/ { $0 =gensub(/(\n *host = )[^\n]*/, "\\1\"new value\"", 1) }
  1' file
  • 使用mawk (不太健壮;也适用于GNU awk):
awk '
  BEGIN{ RS=ORS="}\n" }
  /^section2/ { sub(/ host = [^\n]*/, " host = \"new value\"") }
  1' file

注意:由于使用了多字符RS值,因此这两种解决方案都不适用于BSD / OSX awk;使它工作需要更多的努力。

<强>解释

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

  • /^section2/在每条记录的开头处与文字section匹配。

    • Mawk解决方案:{ sub(/ host = [^\n]*/, " host = \"new value\"") }使用新值替换密钥host的值。

      • 请注意,只需与下一个换行符([^\n]*)匹配,因为只有.*会匹配记录的结尾,并且会有换行符。
      • 最好更健壮地匹配host密钥,例如与 sub("/(\n *host = )...),但您需要捕获组引用以在替换值中保留相同数量的前导空格,sub()不支持。 但是, GNU awk通过其非标准gensub()函数提供捕获组引用;见下文。
    • GNU Awk解决方案:使用非标准gensub()函数可以使用捕获组(\\1指的是第一个捕获的组,...),这使得替换更多健壮,更方便。

      • gensub(),与sub()不同,不会修改输入字符串,而是返回修改后的副本 - 因此需要将其分配给$0。< / LI>
      • 1,因为第3个参数告诉gensub()仅替换 1 事件。
  • 1是简单打印结果记录的常用简写。