Delete the nth line from a matched string (which only occurs once in the file)

I have a question related to deletion of strings that appear at the n+2 position after the matched string which is at position n using awk for multiple files. I am able to print it using the command:

 awk -F '/radius-server/{nr[NR+4]}; NR in nr' *

Where the matched string is radius-server. Since I’m not too familiar with
awk I would appreciate it if someone could help me delete this line in place , that would mean that I want the files to be modified and saved after the deletion is done.
An example scenario is below –
file 1 which is unmodified

 radius-server dz7HQQH4EqT5 1645-1646
 !
 oj5icqh1dGpSK
 !  
 alias exec t telnet
 alias exec sis show interface status
 !

file 2, after modification is –

radius-server dz7HQQH4EqT5 1645-1646
!
!
alias exec t telnet
alias exec sis show interface status
!

I understand that I can do a pattern matching method using sed -i '/pattern/d' to remove it but that is not what I want as the values change from file to file. Any help would be much appreciated.

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

sed seems like the right tool:

sed -i '/radius-server/!b;n;n;d' filename

How it works:

/radius-server/!b # as long as it's NOT 'radius-server' do nothing (branch to end)
n # read next line (replace current line with next line)
n # same as above - we now read 2 lines
d # delete the current line

UPDATE – to modify multiple files, simply use glob instead of filename, e.g.

sed -i '/radius-server/!b;n;n;d' *

Method 2

Unless you have GNU awk 4.1.0 or later…

You won’t have such an option as sed’s -i option so instead do:

for file in *
do
awk -v lines=2 'BEGIN { ignore = -1 } /radius-server/ { ignore = NR + lines } NR != ignore { print }' "$file"
done > result.txt

This works as follows:

BEGIN { ignore = -1 }             # initialize ignore with -1 so NR will never
                                  # be equal to it by accident

/radius-server/ { ignore = NR + lines } # when the radius-server is found, set ignore to the
                                  # line we want to ignore

NR != ignore { print }            # unless the current line is that line, print
                                  # it.

Note: the -i is not magic, it is also creating a temporary file sed just handles it for you.

Update

If you need to recurse into subdirectories:

find . -type f -exec awk ... {} ; > result.txt

In both cases, you should probably put result.txt in a different directory. Otherwise, it will be matched and used as an input file.

Method 3

PATH_TO_FOLDER="/some/path/to/folder/"
FILE_EXTENSION=".ext"
FILES=$(ls ${PATH_TO_FOLDER}/*${FILE_EXTENSION})

for FILE in $FILES; do
FILENAME=$(basename $FILE ${FILE_EXTENSION})
TMP_FILE=${PATH_TO_FOLDER}/${FILENAME}.tmp
awk -v Lines=2 '{if($0~"radius-server"){ 
print;
for(i=0;i<=Lines;i++)
{
getline;
if(i==Lines){
next;
}else{
print; 
}
} 
}
else{
print;
}
}' $FILE > $TMP_FILE
mv ${TMP_FILE} ${FILE}

In principle this should work. Basically if the line contains radius-server that line will be printed and then it will iterate over the next 3 lines 0 will print the first line 1 will print the second line and then 3 will skip the third line altogether. For all other cases the lines are printed as is.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Oldest
Newest Most Voted
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x