如何使用Sed删除之前的5行和模式匹配之后的6行?

时间:2014-09-25 19:06:54

标签: linux unix sed grep

我想在文件中搜索“xxxx”模式,并在此模式前删除5行,在此匹配后删除6行。我怎么能用Sed做到这一点?

4 个答案:

答案 0 :(得分:4)

这是使用awk实现此目的的一种方法。我假设您还想删除该行本身,并且该文件足够小以适应内存:

awk '{a[NR]=$0}/xxxx/{f=NR}END{for(i=1;i<=NR;++i)if(i<f-5||i>f+6)print a[i]}' file

将每一行存储到数组a中。当模式/xxxx/匹配时,保存行号。整个文件处理完毕后,循环遍历数组,只打印想要保留的行。

或者,您可以先使用grep获取行号:

grep -n 'xxxx' file | awk -F: 'NR==FNR{f=$1}NR<f-5||NR>f+6' - file

在这两种情况下,删除的行都将围绕模式匹配的最后一行。

第三种选择是使用grep获取行号,然后使用sed删除行:

line=$(grep -nm1 'xxxx' file | cut -d: -f1)
sed "$((line-5)),$((line+6))d" file

在这种情况下,我还添加了-m开关,以便在找到第一个匹配项后退出grep。

答案 1 :(得分:4)

这可能适合你(GNU sed):

sed ':a;N;s/\n/&/5;Ta;/xxxx/!{P;D};:b;N;s/\n/&/11;Tb;d' file

保持一个5行的滚动窗口,并在遇到指定的字符串时再添加6个(总共11个)并删除。

N.B。这是一个barebones解决方案,很可能需要根据您的特定需求进行定制。问题如:如果整个文件中有多个字符串怎么办?如果字符串在前五行之内或多个字符串在彼此的五行之内等等,那该怎么办。

答案 2 :(得分:1)

如果你知道,行号(不难获得),你可以使用类似的东西:

filename="test"
start=`expr $curr_line - 5`
end=`expr $curr_line + 6`

sed "${start},${end}d" $filename (optionally sed -i)

当然,您必须记住其他条件,例如start不应小于1且结尾大于文件中的行数。

答案 3 :(得分:0)

另一个 - 可能更容易理解 - 解决方案是使用grep来查找关键字和相应的行:

grep -n 'KEYWORD' <file>

然后使用sed来获取行号,如下所示:

grep -n 'KEYWORD' <file> | sed 's/:.*//'

现在您拥有行号,只需使用sed,如下所示:

sed -i "$(LINE_START),$(LINE_END) d" <file>

删除之前和/或之后的行!仅使用-i,您将覆盖<file>(无备份)。

脚本示例可能是:

#!/bin/bash

KEYWORD=$1
LINES_BEFORE=$2
LINES_AFTER=$3
FILE=$4

LINE_NO=$(grep -n $KEYWORD $FILE | sed 's/:.*//' )
echo "Keyword found in line: $LINE_NO"

LINE_START=$(($LINE_NO-$LINES_BEFORE))
LINE_END=$(($LINE_NO+$LINES_AFTER))
echo "Deleting lines $LINE_START to $LINE_END!"

sed -i "$LINE_START,$LINE_END d" $FILE

请注意,仅当找到关键字一次时,此功能才有效!根据您的需要调整脚本!