SED:跳过几行后删除模式匹配后的行,然后删除模式行

时间:2015-09-23 20:37:29

标签: regex bash sed

假设我想在模式之后删除一些行,同时跳过其间的一些行,然后删除带有模式本身的行。我可以使用以下两个命令来完成此操作:

sed -i '/PATTERN/{n;n;n;n;n;n;N;N;N;N;d}' file  # match pattern, skip 5 lines, then delete 5 consecutive lines
sed -i /PATTERN/d file  # delete line with pattern

但我想在一个命令中执行此操作。这里的问题很明显,因为模式更改会影响两个表达式,因此必须在单个表达式中指定更改。有没有办法实现这个目标?

更新

示例输入:

...
ifeq ($(ose),)
    dh_installdocs \
        $(archdir)/UserManual*.pdf $(archdir)/VirtualBox*.chm \
        $(addprefix $(archdir)/, LICENSE)
    rm $(addprefix $(archdir)/,UserManual*.pdf VirtualBox*.chm \
        LICENSE)
else
    dh_installdocs \
        $(archdir)/UserManual*.pdf
    rm $(addprefix $(archdir)/,UserManual*.pdf)
endif
...

示例输出:

...
    dh_installdocs \
        $(archdir)/UserManual*.pdf $(archdir)/VirtualBox*.chm \
        $(addprefix $(archdir)/, LICENSE)
    rm $(addprefix $(archdir)/,UserManual*.pdf VirtualBox*.chm \
        LICENSE)
...

更新2:

可以在此处获取示例文件:http://download.virtualbox.org/virtualbox/5.0.4/VirtualBox-5.0.4.tar.bz2 debian / rules

4 个答案:

答案 0 :(得分:2)

要求救援!

awk 's&&s--{print;next} d&&d--{next} /pattern/{d=5;s=5;next} 1'

使用Ed Morton的smart counters

为跳过设置s,为删除设置d

对于你的模式,你需要逃脱特殊的字符

awk 's&&s--{print;next} d&&d--{next} /\(\$\(ose\),\)/{d=5;s=5;next} 1'

答案 1 :(得分:1)

如果它不是sed我会提出perl可以在" sed模式"并使用正则表达式和一些更复杂的脚本逻辑。

E.g。一个for循环:

#!/usr/bin/env perl
use strict;
use warnings;

while ( <DATA> ) {
   if ( m/ifeq\ \(\$\(ose\)\,\)/ ) {

       print "". <DATA> for 1..5;
       <DATA> for ( 1..5 );
   }
   else { print };
}

__DATA__
...
ifeq ($(ose),)
    dh_installdocs \
        $(archdir)/UserManual*.pdf $(archdir)/VirtualBox*.chm \
        $(addprefix $(archdir)/, LICENSE)
    rm $(addprefix $(archdir)/,UserManual*.pdf VirtualBox*.chm \
        LICENSE)
else
    dh_installdocs \
        $(archdir)/UserManual*.pdf
    rm $(addprefix $(archdir)/,UserManual*.pdf)
endif
...

你可以做什么&#39;内联&#39;像sed:

perl -i -ne 'if ( m/ifeq\ \(\$\(ose\)\,\)/ ) { print "". <> for 1..5; <> for ( 1..5 );} else {print}'

或者,您可以使用perl&#34;范围运算符&#34;检测你是否在两种模式之间。这更多地取决于你的文件的其余部分(我假设&#39;其他&#39; ...&#39; endif&#39;并非完全不常见)。

答案 2 :(得分:1)

以下是使用awk的方法:

awk '/ifeq/ { n = 6; next } n && !--n { c = 1 } c && c++ < 6 { next }1' file

看起来有点棘手,但逻辑如下:

  • 当模式/ifeq/匹配时,将变量n设置为6并跳过该行
  • n && !--n仅在n为1时才为真(以这种方式编写,以便n仅递减直到达到0)
  • 设置c后,跳过每一行,直到c达到6
  • 最后
  • 1表示打印任何未跳过的行(默认操作为
    { print }

答案 3 :(得分:1)

另一种方法:

sed '/($(ose),)/,/^endif/{/($(ose),)/d;/^else/,/^endif/d}' file

输出:

...
    dh_installdocs \
        $(archdir)/UserManual*.pdf $(archdir)/VirtualBox*.chm \
        $(addprefix $(archdir)/, LICENSE)
    rm $(addprefix $(archdir)/,UserManual*.pdf VirtualBox*.chm \
        LICENSE)
...

添加选项-i以“编辑”。