我有一个包含以下内容的文件:
[...]
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 自动循环遍历输入文件并打印每一行。1
location /static
0
}
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
负责注释掉块中的各个行,无论它可能包含多少行。然后打印出该块(连同前导位置关键字)。否则,将提取一行(直到换行符为止)并原封不动地打印出来。
其他一些注意事项:
$in
通过取消定义记录分隔符,将文本全部读取并存储在字符串 ( ) 中$/
$1
是保存用括号分隔的正则表达式内容的特殊变量;例如,对于(location\s+\S+\s+)
,$1 包含文本location /static
(包括尾随空格)。