How to delete 5 lines before and 6 lines after pattern match using Sed?

核能气质少年 提交于 2020-01-13 06:02:16

问题


I want to search for a pattern "xxxx" in a file and delete 5 lines before this pattern and 6 lines after this match. How can i do this using Sed?


回答1:


This might work for you (GNU sed):

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

Keep a rolling window of 5 lines and on encountering the specified string add 6 more (11 in total) and delete.

N.B. This is a barebones solution and will most probably need tailoring to your specific needs. Questions such as: what if there are multiple string throughout the file? What if the string is within the first five lines or multiple strings are within five lines of each other etc etc etc.




回答2:


Here's one way you could do it using awk. I assume that you also want to delete the line itself and that the file is small enough to fit into memory:

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

Store every line into the array a. When the pattern /xxxx/ is matched, save the line number. After the whole file has been processed, loop through the array, only printing the lines you want to keep.

Alternatively, you can use grep to obtain the line number first:

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

In both cases, the lines deleted will be surrounding the last line where the pattern is matched.

A third option would be to use grep to obtain the line number then use sed to delete the lines:

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

In this case I've also added the -m switch so grep exits after finding the first match.




回答3:


if you know, the line number (what is not difficult to obtain), you can use something like that:

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

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

of course, you have to remember about additional conditions like start shouldn't be less than 1 and end greater than number of lines in file.




回答4:


Another - maybe more easy to follow - solution would be to use grep to find the keyword and the corresponding line:

grep -n 'KEYWORD' <file>

then use sed to get the line number only like this:

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

Now that you have the line number simply use sed like this:

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

to remove lines before and/or after! With only the -i you will override the <file> (no backup).

A script example could be:

#!/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

Please note that this will work only if the keyword is found once! Adapt the script to your needs!



来源:https://stackoverflow.com/questions/26046210/how-to-delete-5-lines-before-and-6-lines-after-pattern-match-using-sed

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!