【问题标题】:Delete Lines : after pattern1 and between pattern2 and pattern3 using awk/sed/perl删除行:在 pattern1 之后以及在 pattern2 和 pattern3 之间使用 awk/sed/perl
【发布时间】:2012-06-13 04:05:16
【问题描述】:

我需要从文件中删除 pattern1 之后pattern 2 和 pattern3 之间的行,如下所示:

aaaaaaaa 
bbbbbbbb
pattern1   <-----After this line
cdededed
ddededed
pattern2
fefefefe   <-----Delete this line
efefefef   <-----Delete this line
pattern3
adsffdsd
huaserew

请您建议如何使用 awk 或 sed 或在 perl 中完成此操作。

【问题讨论】:

  • 如果 pattern1 出现在 pattern2 之后,是否应该删除?

标签: perl sed awk


【解决方案1】:
sed '/pattern1/,${ /pattern2/,/pattern3/{/pattern2/b; /pattern3/b; d;} };' file

格式化:

/pattern1/,$ {
    /pattern2/,/pattern3/ {
        /pattern2/b;
        /pattern3/b; 
        d;
    } 
}

解释:

  • /pattern1/,$pattern1 之后到文件末尾的行范围
  • /pattern2/,/pattern3/pattern2pattern3 之间的行范围
  • /pattern2/b;/pattern3/b; 跳过 pattern2pattern3 行,否则它们会包含在范围内(请参阅 the sed faq
  • d 删除范围内的其他行

更新

从 cmets 可以重写内部块:

//!d

地点:

  • //(空模式)匹配最后使用的正则表达式(在本例中为 pattern2pattern3
  • ! 反转下一个命令,使其适用于与模式匹配的所有除了
  • d 删除这些行

所以完整的重写模式是:

/pattern1/,$ {
    /pattern2/,/pattern3/ {
        //!d
    } 
}

【讨论】:

  • 我同意;这是sed的限制。没有更好的方法来做到这一点(在 sed 中)。 awk 和 perl 肯定有更优雅的解决方案。
  • @glennjackman:你不需要重复这个模式:sed '/pattern1/,${ /pattern2/,/pattern3/{//b; d;} };'
  • @DennisWilliamson //b;d 可以替换为 //!d
  • @potong,丹尼斯威廉姆森;我很高兴被证明是错误的,因为没有更优雅的解决方案;我已将您的建议整合到答案中。
【解决方案2】:

像状态机一样使用 awk:

awk '
    BEGIN {print_line = 1}
    /pattern1/ {consider = 1}
    consider && /pattern2/ {print_line = 0; print}
    consider && /pattern3/ {print_line = 1}
    print_line {print}
' filename

【讨论】:

    【解决方案3】:

    如果您正在使用 perl 在命令行上寻找快速解决方案,那么这是 flip-flop 运算符的理想情况。现在,有两种方法可以在极端情况下解释这个问题——只要pattern1 出现在pattern2 之前,这两种方法的功能都是一样的:

    1. 如果 pattern1pattern2 之后但在 pattern3 之前,则删除 pattern1 之间的所有内容>pattern3

    2. 或者,如果 pattern1pattern2 之后但在 pattern3 之前什么也不做除非你看到另一个模式1

    在我们开始之前,请注意 perl 争论 -p

    -n                assume "while (<>) { ... }" loop around program
    -p                assume loop like -n but print line also, like sed
    

    现在,首先,我给你..

    perl -pe'$x ||= /7/; $_= "" if /5/ .. /8/ and $x' <(seq 1 10)
    1
    2
    3
    4
    5
    6
    9
    10
    

    $x ||= /7/:当$xfalse 时,这会将$x 设置为/7/ 的返回值。 /7/ 将在匹配时返回 true。这意味着$x 在第一次匹配时被设置为真,而||= 的本质是永远不会在变量已经为真时设置它。

    如果范围在/5//8/ 之间并且它已经将$x 设置为true,那么它设置$_ = ''。记住短路的工作方式:a &amp;&amp; b 表示仅当a 评估为true 时才运行b。在这种情况下,评估a 的事实将设置触发器操作符的状态——这就是我们想要的;然而,我们只希望 $_ = '' 在已经看到 7 时出现。

    现在,对于问题的第二种解释,只需切换顺序...

    perl -pe'$x ||= /7/; $_= "" if $x and /5/ .. /8/' <(seq 1 10)
    

    这将打印整个范围。 Perl 在找到/7/ 之前不会开始寻找/5/。在我们的连续范围内,这不会发生。

    顺便说一句,要真正让其中一些答案感到羞耻,许多空格是不需要的......

    perl -pe'$x||=/2/;$_=""if$x&&/5/../8/' # secksey
    

    【讨论】:

    • 我不会以任何一种方式解释这个问题。这个问题清楚地表明,pattern1 出现在 pattern2 之前。
    • @DennisWilliamson 两个都处理得很好。
    • @DennisWilliamson 我仍然没有看到pattern1pattern2 之前出现在问题中,这个例子有,但它可能是偶然的。 我需要从文件中删除模式1 之后和模式2 和模式3 之间的行 为什么pattern1 不能在pattern2pattern3 之间?设置删除范围从pattern1pattern3
    • @tchrist 不要害怕,我有plenty of answers你可以投票!
    • 触发器运算符很吸引人,但是这个解决方案还删除了pattern2pattern3,它们是不会被删除的。此外,这个解决方案实际上输给了代码高尔夫中的 sed:sed '/3/,${/5/,/8/{//!d}} 只有 21 个字符,而 28 个。
    【解决方案4】:

    完成罗塞塔石碑:

    perl -ne '++$saw_pattern1 if /pattern1/;
              $inside = ($saw_pattern1 && /pattern2/) .. /pattern3/;
              print unless $inside && ($inside > 1 && $inside !~ /E0$/)' \
      input
    

    代码利用了 Perl 的 .. range operator

    在标量上下文中,.. 返回一个布尔值。该运算符是双稳态的,就像一个触发器,并模拟 sedawk 和各种编辑器的行范围(逗号)运算符。每个.. 运算符都维护自己的布尔状态,即使在调用包含它的子例程时也是如此。只要其左操作数为假,它就为假。一旦左操作数为真,范围运算符保持为真,直到右操作数为真,之后,范围运算符再次变为假。直到下一次评估范围运算符时它才会变为假……

    当运算符处于假状态时不计算右操作数,而当运算符处于真状态时不计算左操作数。优先级略低于||&amp;&amp;。返回的值要么是空字符串(表示 false),要么是序列号(以 1 开头)表示 true。对于遇到的每个范围,都会重置序列号。范围中的最终序列号附加了字符串E0,这不会影响其数值,但如果您想排除端点,则可以搜索一些内容。等待序列号大于1即可排除起点。

    【讨论】:

    【解决方案5】:

    这可能对你有用:

    sed '/pattern1/,$!b;/pattern2/,/pattern3/!b;//!d' file
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-08-11
      • 1970-01-01
      • 1970-01-01
      • 2014-06-27
      相关资源
      最近更新 更多