我想在文件中搜索“xxxx”模式,并在此模式前删除5行,在此匹配后删除6行。我怎么能用Sed做到这一点?
答案 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
请注意,仅当找到关键字一次时,此功能才有效!根据您的需要调整脚本!