如何使用 sed 或 awk 注释掉与正则表达式匹配的多行

如何使用 sed 或 awk 注释掉与正则表达式匹配的多行

我有一个包含以下内容的文件:

[...]

location /static {
    ...
    multiple lines
    ...
}

[...]

location /static/ {
    ...
    multiple lines
    ...
}

[...]

我想要得到:

[...]

# location /static {
#     ...
#     multiple lines
#     ...
# }

[...]

# location /static/ {
#     ...
#     multiple lines
#     ...
# }

[...]

我怎样才能将我的文件发送给unix命令?

答案1

这不是一件容易的事。如果你能假设每个{}块不包含其他嵌套块,{}那就更容易了,你可以这样做:

perl -pe 'if(/location\s*\/static/){$n=1}elsif(/}/){$n=0} s/^/#/ if $n==1;' file

如果当前行匹配,则将设置$n为,如果在 之后找到第一个 ,则将其重新设置为。然后,只要,它就会将 添加到行首。该标志使 perl 自动循环遍历输入文件并打印每一行。1location /static0}location/static$n==1#-p

现在,如果你可以在要注释的块内有任意深度嵌套的块,事情就会变得更加复杂。例如,如果你有这样的内容:

location /static {
   if(foo){
      print "one";
   }
   elsif(bar){
      print "two";
   }
}

对于这种情况,上面的简单解决方案将失败,您将必须使用一个跟踪打开数量的解决方案{。 例如(这实际上是一行代码,您可以直接复制/粘贴到您的终端中,我只是为了清楚起见将其扩展了):

perl -pe 'if(/location\s*\/static/){$n=1;}
          elsif(/}/ && $open==0){$n=0} 
          if($n==1 && /{/){$open++} ## count open brackets
          elsif($n==1 && /}/){$open--} ## count closing brackets
          if($n==1 && $open>0){ s/^/#/}; ' file

最后,如果解决方案按预期工作,您可以添加标志-i对文件本身进行更改:

perl -i -pe 'if(/location\s*\/static/){$n=1}elsif(/}/){$n=0} s/^/#/ if $n==1;' file

答案2

使用正则表达式提取(可能嵌套的)分隔块并不特别有趣或容易。不过,有一个优雅的解决方案,使用一个已经随 Perl 一起提供很长时间的模块(因为 Perl 是您的标签之一),即。文字::平衡

#!/usr/bin/env perl
use strict;
use warnings;
use Text::Balanced qw( extract_bracketed );

my $in = do { local $/ = undef; <> };
while( $in ) {
    my $out;
    if    ( $in =~ s/^(location\s+\S+\s+)// ) { ( $out = $1 . extract_bracketed($in) ) =~ s/^/# /mg }
    elsif ( $in =~ s/^(.*[\r\n]*)// )         { $out = $1 }
    print $out;
}

该脚本的工作原理是反复使用(提取)和分析字符串的前导部分,直到不剩任何内容:

  • 如果前导部分包含location关键字,后跟空格(\s+),以及看起来像是标识符的内容(目前非常粗略地通过它是非空格字符序列来识别,\S+),extract_bracketed则将提取后面的分隔块(默认情况下,它将提取由以下任何对分隔的块:[]{}()<>extract_bracketed将正确处理要提取的块内的嵌套、平衡分隔符。以下替换s/^/# /mg负责注释掉块中的各个行,无论它可能包含多少行。然后打印出该块(连同前导位置关键字)。

  • 否则,将提取一行(直到换行符为止)并原封不动地打印出来。

其他一些注意事项:

  1. $in通过取消定义记录分隔符,将文本全部读取并存储在字符串 ( ) 中$/
  2. $1是保存用括号分隔的正则表达式内容的特殊变量;例如,对于(location\s+\S+\s+),$1 包含文本location /static(包括尾随空格)。

相关内容