【问题标题】:How do I delete a matching line, the line above and the one below it, using sed?如何使用 sed 删除匹配的行,上一行和下一行?
【发布时间】:2010-10-26 23:04:42
【问题描述】:

我在一个文件中多次出现以下序列:

yyyy
xxxx
zzzz

我有一个匹配xxxx 的正则表达式。每当有匹配时,我想删除该行,之前的行(例如yyyy)和之后的行(例如zzzz)。我如何使用 sed 来做到这一点?

【问题讨论】:

    标签: regex sed


    【解决方案1】:

    诀窍是将看到的最后一行存储在“保持空间”中。

    sed -n '
    /^xxxx/{n
            n
            x
            d
           }
    x
    1d
    p
    ${x
      p
     }
    ' <input file>
    

    x 开始 - 用保留空间 (x) 交换当前输入行,然后第一行不打印任何内容 (1d),后续行打印刚刚从保留空间(p),在最后一行再次交换保留空间并打印其中的内容($x{x p}。当我们到达目标行(从 /^xxxx/ 开始)时,剩下的就是要做的事情 - 阅读接下来的两个行进入模式空间 (n n) 并将模式空间与保持空间 (x) 交换 - 这将保持空间留给我们要打印的下一行,将模式空间留给匹配前的行,我们不想要,所以我们放弃它 (d)

    【讨论】:

    • “x”命令的进一步解释,它用保持缓冲区“交换”模式空间:grymoire.com/Unix/Sed.html#uh-53
    • 我无法运行上述脚本。它说 sed: FUNCTION /^pattern/{n n x d } x 1d p ${x p } 无法解析不知道为什么?
    【解决方案2】:

    这就是我在 perl 中的做法,也许它可以帮助你走上正确的轨道……祝你好运!

    open(INFILE,"<in.txt");
    my(@arrayOutBoundData, $skipNextLine)l
    for (<INFILE>) {
        if (not $skipNextLine) {
            if (/^xxxx$/) {
                pop(@arrayOutBoundData);
                $skipNextLine = 1;
            } else {
                push(@arrayOutBoundData,$_);
            }
        }
    $skipNextLine = 0
    }
    
    open(OUTFILE,">out.txt");
    for (@arrayOutBoundData) {
        print OUTFILE;
    }
    

    (未在此系统上测试没有 perl,请原谅任何过度站点。)

    【讨论】:

      【解决方案3】:

      您可以查看this document。它涵盖了使用sed 处理多行。

      【讨论】:

        【解决方案4】:

        您可以使用以下内容:

        sed -n '/xxxx/{N;s/.*//;x;d;};x;p;${x;p;}'
        

        这会将 3 行替换为 1 个空行。

        【讨论】:

          【解决方案5】:

          可以先反转文件,使用sed删除匹配的行和下一行(或sed命令中的+Nd行),最后将结果反转回来:

          tac old.file | sed -e '/xxxx/,+1d' | tac > new.file
          

          【讨论】:

            【解决方案6】:

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

            echo -e "a\nyyyy\nxxxx\nzzzz\nb" | sed 'N;/^xxxx/M{/^xxxx/d;$!N;d};P;D'
            a
            b
            

            这会在模式空间中保留一个包含两行的窗口,如果在第一行或第二行中找到所需的正则表达式,则读取下一行,然后删除所有三行。边缘情况是如果在之前/之后没有行的情况下在第一行或最后一行中找到正则表达式。在这些情况下,只能删除两行。

            顺便说一句,这个解决方案可能在 GNU sed 中发现了一个可能的错误。地址的M 标志允许^$ 元字符在正则表达式中用作多行字符串中行首和行尾的零长度标记。空地址// 重用了之前声明的地址。该地址应该是包含多行标志的地址吗?目前它似乎包括标志,即使它没有说明,即

            sed 'N;/^xxxx/M{/^xxxx/d;$!N;d};P;D' file
            

            产生不同的(正确的)结果:

            sed 'N;/^xxxx/M{//d;$!N;d};P;D' file
            

            如果xxxx 出现在文件的第二行。

            【讨论】:

            • 差不多,但他也希望 zzzz 消失。
            【解决方案7】:
            grep -v -f <(grep -1 "xxxx" file) file
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2015-04-18
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2013-03-04
              • 1970-01-01
              相关资源
              最近更新 更多