【问题标题】:SED: Delete X Lines After a MatchSED:匹配后删除 X 行
【发布时间】:2019-05-10 15:31:19
【问题描述】:

我正在尝试使用sed 删除一个范围。范围来自已知匹配和接下来的 2 行。假设我想删除所有以Don't 开头的行,然后是后面的 2 行。

请注意,我也在 sed 命令文件中进行替换。因此,我避免在我的解决方案空间中使用-n/p

无论出于何种原因,我都想限制自己只调用一次 sed。

这是我的数据(data.txt):

Print Me
Please Output This line
Don't Print Me and 2 more lines
This line is no good
So is this one
We should see this line
And this one, too.

这是我的预期输出:

Print Me
Please Output This line
We should see this line
And this one, too.

这是一个尝试:

sed -f delete_dont_plus_2.sed data.txt

以此为delete_dont_plus_2.sed:

/^Don't/,+2d

这是我的结果:

sed: 1: delete_dont_plus_2.sed: expected context address

我也试过这些:

/^Don't/,/^Don't/+2d
/^Don't/,{/^Don't/+2}d

这个问题的第二种方法:

假设我们想让这段代码更健壮一些。今天还有2行需要删除,但谁知道将来会有多少行。假设我们要删除最多但不包括We should see this line。在这个问题的变体中,结果完全相同。同样,让我们​​考虑一个有限的 BSD sed,因此我们不能使用像 /^Don't/,/^We should see this line/-1d 这样的表达式。

谢谢!

【问题讨论】:

    标签: macos sed


    【解决方案1】:

    您可能使用的 sed 不支持 regexp,+n 形式的地址。以下是针对这种特殊情况的解决方法:

    /^Don't/{N;N;d;}
    

    当找到^Don't 时,它只是将另外两行读入模式空间并将它们完全删除。

    但无论如何,我认为 sed 不是正确的工具,您应该改用 。例如:

    awk '/^Don\047t/{c=2;next} !(c&&c--)' file
    

    c.f:Printing with sed or awk a line following a matching pattern


    假设我们要删除最多但不包括We should see this line。在这个问题的变体中,结果完全相同。

    使用 sed 你需要写两次相同的 RE:

    /^Don't/,/^We should see this line/{/^We should see this line/!d;}
    

    使用 awk 你甚至不需要 RE:

    awk 'index($0,"Don\047t")==1{d=1} $0=="We should see this line"{d=0} !d' file
    

    【讨论】:

    • 为我工作。我不得不为其添加一点 MAC 乐趣:/^Don't/{N;N;d;}(即最后一个半)。我也很欣赏 awk 的回答。 awk 几乎总是我的首选工具(与 sed 相比)。但是,我已经有一个很大的 sed 命令文件,其中大部分是替换的,所以我受到了限制。感谢您的帮助
    • 我听到了,但不能代表我社区中的所有其他 mac 用户发言。从某种意义上说,我坚持最低公分母。再次感谢您的帮助。作为一个额外的问题,如果我们不知道要删除多少行,脚本将如何更改。相反,我们想删除最多但不包括以这样开头的第一行 '/^We should see this line/'。对于这个问题的变体,输出应该是相同的。
    • 对于 awk,另见:*.com/questions/17908555/…
    • 当正则表达式是最后一行或倒数第二行时,此解决方案可能不起作用,因为 N 指令将尝试读取文件末尾并失败,打印模式空间中的内容.也许sed '/^Don't/{$!N;$!N;d;}' file 会阻止这种情况。
    【解决方案2】:

    使用 GNU sed:

    sed "/^Don't/,+2d" file
    

    输出:

    打印我 请输出这一行 我们应该看到这条线 还有这个。

    【讨论】:

      【解决方案3】:

      这可能对你有用(GNU sed):

      sed '/^Don'\''t/{s/.*/X/;h;d};x;/X/!{x;b};s/^/X/;/^XXX/z;x;d' file
      

      此解决方案从遇到正则表达式时开始计数。

      注意如果正则表达式后面的两行之一也是正则表达式,则重新开始计数。

      一个较少 GNU 特定和程序化的解决方案:

      sed '/^Don'\''t/{s/.*/X/;h;d};x;/X/!{x;b};s/^/X/;/^XX\{2\}/s/.*//;x;d' file
      

      【讨论】: