如何使用sed删除匹配行及其上下行?

13

我在一个文件中多次遇到以下序列:

yyyy
xxxx
zzzz

我有一个正则表达式可以匹配 xxxx。每当有匹配时,我想要删除该行、前一行(例如 yyyy)和后一行(例如 zzzz)。我怎样使用sed实现这个功能?

```bash sed -i '/xxxx/{N;N;d}' file.txt ```
其中file.txt是需要处理的文件名。该命令会在找到匹配的xxxx字符串时,将该行、前一行和后一行都删除。
7个回答

15
关键是将上一行记录在“保留空间”中。
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” 命令的进一步解释,该命令将模式空间与保持缓冲区进行“交换”:http://www.grymoire.com/Unix/Sed.html#uh-53 - Ben Lever
我无法运行上述脚本。它显示 "sed: 函数 /^pattern/{n n x d } x 1d p ${x p }" 无法解析,不确定原因是什么。 - oortcloud_domicile

1
这是一个使用ed的一行解决方案:
ed -s input.txt <<< '/xxxx/ -1, /xxxx/ +1 d'$'\n'w

这份代码因其优雅简洁而应该得到更多赞,尽管它可能没有完全满足要求(那么删除下一行怎么办?) - mbrandalero

0

这个可能适合你(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消失。 - Samuel Edwin Ward

0
你可以使用以下内容:
sed -n '/xxxx/{N;s/.*//;x;d;};x;p;${x;p;}'

这将用一行空白行替换3行。


0

这是我在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,请原谅任何疏忽。)


-1
grep -v -f <(grep -1 "xxxx" file) file

-1
您可以查看 此文档。它涵盖了使用 sed 处理多行的内容。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接