我在一个文件中多次遇到以下序列:
yyyy
xxxx
zzzz
我有一个正则表达式可以匹配 xxxx
。每当有匹配时,我想要删除该行、前一行(例如 yyyy
)和后一行(例如 zzzz
)。我怎样使用sed实现这个功能?
其中file.txt是需要处理的文件名。该命令会在找到匹配的xxxx字符串时,将该行、前一行和后一行都删除。
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
)。
这个可能适合你(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
。
sed -n '/xxxx/{N;s/.*//;x;d;};x;p;${x;p;}'
这将用一行空白行替换3行。
这是我在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,请原谅任何疏忽。)
grep -v -f <(grep -1 "xxxx" file) file