sed - 在模式之间应用替换

sed - apply substitution between patterns

我有两个模式 STARTEND,我想用这些模式之间的下划线替换每个 space。

示例

Lorem ipsum dolor START sit amet, consectetur END adipiscing elit.

应该改成

Lorem ipsum dolor START_sit_amet,_consectetur_END adipiscing elit.

我知道用下划线

替换每个space的正则表达式
sed 's/ /_/g'

而且我也知道如何匹配两个模式之间的部分

sed 's/.*START\(.*\)END.*//g'

但我不知道如何将这两件事结合起来。

您可以使用此 awk 来完成您的工作:

awk -v ts='START ' -v te='END ' '{
   while (n = index([=10=], ts)) {
      m = index([=10=], te)
      if (m > n) {
         s = substr([=10=], n, m-n)
         gsub(/[[:blank:]]+/, "_", s)
         [=10=] = substr([=10=], 1, n-1) s substr([=10=], m)
      }
   }
} 1' file

Lorem ipsum dolor START_sit_amet,_consectetur_END adipiscing elit.

作为替代,您可以使用 Perl:

perl -pe 's/(START.*?END)/=~s#\s#_#gr/ge'

(START.*?END) 模式匹配 STARTEND 之间的子字符串,同时将其捕获到第 1 组,然后 s#\s#_#gr 替换每个空格(\s ) 在组的内容中包含 _

或者,如果您使用的 Perl 不支持 r 选项:

perl -pe 's/(?:START|\G(?!^))(?:(?!END).)*?\K\s/_/g'

参见online demo and the second regex demo online

(?:START|\G(?!^))(?:(?!END).)*?\K\s 匹配

  • (?:START|\G(?!^)) - START 子字符串或上一次成功匹配的结尾(与 \G(?!^)
  • (?:(?!END).)*? - 除换行符以外的任何字符,不开始 END 子字符串,尽可能少
  • \K - 匹配重置运算符丢弃先前匹配的文本
  • \s - 一个空白字符。

使用 GNU awk:

awk -v RS='(START|END)' 'RT=="END"{gsub(" ","_")}{printf "%s%s",[=10=],RT}' file

这取决于设置为 STARTEND 的记录分隔符 RS

如果到达 END 标记,记录将更新为使用函数 gsub().

将空格替换为下划线

最后一条语句打印整个记录,包括记录终止符 RT(与 RS 匹配)。

请注意,此解决方案允许 STARTEND 跨不同的行(并且必须在同一行上)。