简体   繁体   中英

Using sed to delete specific lines after LAST occurrence of pattern

I have a file that looks like:

this name
this age

Remove these lines and space above.
Remove here too and space below

Keep everything below here. 

I don't want to hardcode 2 as the number of lines containing "this" can change. How can I delete 4 lines after the last occurrence of the string. I am trying sed -e '/this: /{n;N;N;N;N;d}' but it is deleting after the first occurrence of the string.

Could you please try following.

awk '
FNR==NR{
  if($0~/this/){
    line=FNR
  }
  next
}
FNR<=line || FNR>(line+4)
'  Input_file Input_file

Output will be as follows with shown samples.

this: name
this: age
Keep everything below here.

You can also use this minor change to make your original sed command work.

sed '/^this:/ { :k ; n ; // b k ; N ; N ; N ; d }' input_file

It uses a loop which prints the current line and reads the next one ( n ) while it keeps matching the regex (the empty regex // recalls the latest one evaluated, ie /^this:/ , and the command bk goes back to the label k on a match). Then you can append the next 3 lines and delete the whole pattern space as you did.

Another possibility, more concise, using GNU sed could be this.

sed '/^this:/ b ; /^/,$ { //,+3 d }' input_file

This one prints any line beginning with this: ( b without label goes directly to the next line cycle after the default print action).

On the first line not matching this: , two nested ranges are triggered. The outer range is "one-shot". It is triggered right away due to /^/ which matches any line then it stays triggered up to the last line ( $ ). The inner range is a "toggle" range. It is also triggered right away because // recalls /^/ on this line (and only on this line, hence the one-shot outer range) then it stays trigerred for 3 additional lines (the end address +3 is a GNU extension). After that, /^/ is no longer evaluated so the inner range cannot trigger again because // recalls /^this:/ (which is short cut early).

This might work for you (GNU sed):

sed -E ':a;/this/n;//ba;$!N;$!ba;s/^([^\n]*\n?){4}//;/./!d' file 

If the pattern space (PS) contains this , print the PS and fetch the next line.

If the following line contains this repeat.

If the current line is not the last line, append the next line and repeat.

Otherwise, remove the first four lines of the PS and print the remainder.

Unless the PS is empty in which case delete the PS entirely.

NB This only reads the file once. Also the OP says

How can I delete 4 lines after the last occurrence of the string

However the example would seem to expect 5 lines to be deleted.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM