簡體   English   中英

SED:在模式匹配后刪除行,同時跳過幾行,然后刪除模式行

[英]SED: delete lines after pattern match while skipping a few lines, then delete the pattern line

假設我要刪除模式后的某些行,同時跳過它們之間的某些行,然后刪除具有模式本身的行。 我可以使用以下兩個命令來執行此操作:

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.bz2debian / rules

敬請解救!

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

使用Ed Morton的智能計數器將s設置為跳過,將d設置為刪除

對於您的模式,您需要轉義特殊字符

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

如果不需要sed我將提供perl可以在“ sed模式”下工作,並使用正則表達式以及一些更復雜的腳本邏輯。

例如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
...

您可以像sed一樣“內聯”:

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

另外,您可以使用perl的“范圍運算符”來檢測您是否處於兩種模式之間。 不過,這更多地取決於文件的其余部分(我認為'else'...'endif'並不罕見)。

這是使用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 }

另一種方法:

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以“就地”編輯。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM