How to delete all lines before the first and after the last occurrence of a string?

纵然是瞬间 提交于 2021-01-02 06:00:26

问题


cat grab.txt

My Dashboard
Fnfjfjf. random test
00:50

1:01:56
My Notes
No data found.

                                
Change Language                                                                                                                  + English                                                          

Submit


Estimation of Working Capital Lecture 1

Estimation of Working Capital Lecture 2

Estimation of Working Capital Lecture 3

Money Market Lecture 254

Money Market Lecture 255

Money Market Lecture 256

International Trade Lecture 257

International Trade Lecture 258

International Trade Lecture 259
Terms And Conditions
84749473837373
Random text fifjfofifofjfkfkf

I need to filter this text after doing the following

  1. Delete all lines before the first occurrence of word - Lecture
  2. Delete all lines after the last occurrence of word - Lecture
  3. Remove all empty lines

Expected output

Estimation of Working Capital Lecture 1
Estimation of Working Capital Lecture 2
Estimation of Working Capital Lecture 3
Money Market Lecture 254
Money Market Lecture 255
Money Market Lecture 256
International Trade Lecture 257
International Trade Lecture 258
International Trade Lecture 259

What have I tried so far?

cat grab.txt | sed -r '/^\s*$/d; /Lecture/,$!d'

After searching for a bit and some trial-error, I am able to remove empty lines and remove all lines before the first occurrence but unable to remove all lines after the last occurrence.

Note - Even tho my existing command is using sed, its fine if the answer is in awk, perl or grep


回答1:


Could you please try following. Written and tested with shown samples with GNU awk.

awk '
/Lecture/{
  found=1
}
found && NF{
  val=(val?val ORS:"")$0
}
END{
  if(val){
    match(val,/.*Lecture [0-9]+/)
    print substr(val,RSTART,RLENGTH)
  }
}'  Input_file

Explanation: Adding detailed explanation for above.

awk '                                        ##Starting awk program from here.
/Lecture/{                                   ##Checking if a line has Lecture keyword then do following.
  found=1                                    ##Setting found to 1 here.
}
found && NF{                                 ##Checking if found is SET and line is NOT NULL then do following.
  val=(val?val ORS:"")$0                     ##Creating va and keep adding its value in it.
}
END{                                         ##Starting END block of this code here.
  if(val){                                   ##Checking condition if val is set then do following.
    match(val,/.*Lecture [0-9]+/)            ##Matching regex till Lecture digits in its value.
    print substr(val,RSTART,RLENGTH)         ##Printing sub string of matched values here to print only matched values.
  }
}' Input_file                                ##Mentioning Input_file name here.



回答2:


Simply using grep 'Lecture' file with the input you have shown in file will work:

$ grep 'Lecture' file
Estimation of Working Capital Lecture 1
Estimation of Working Capital Lecture 2
Estimation of Working Capital Lecture 3
Money Market Lecture 254
Money Market Lecture 255
Money Market Lecture 256
International Trade Lecture 257
International Trade Lecture 258
International Trade Lecture 259

(note: this simply grabs all the lines containing Lecture. See @RavinderSingh13 answer for protecting against non-Lecture lines in between)




回答3:


You could replace matches of the following regular expression (with the multiline flag set) with empty strings using your tool of choice. The regex engine need only support negative lookaheads.

\A(?:^(?!.*\bLecture\b).*\r?\n)*|^\r?\n|^.*\r?\n(?![\s\S]*\bLecture\b)

Start your engine!

The regex engine performs the following operations.

\A                  : match beginning of string (not line)    
(?:                 : begin a non-capture group
  ^                 : match beginning of line
  (?!.*\bLecture\b) : assert the line does not contain 'Lecture'
  .*\r?\n           : match the line
)                   : end non-capture group
*                   : execute the non-capture group 0+ times
|                   : or
^\r?\n              : match an empty line
|                   : or
^.*\r?\n            : match a line
(?!                 : begin a negative lookahead
  [\s\S]*           : match 0+ characters, including line terminators
  \bLecture\b       : match 'Lecture'
)                   : end negative lookahead



回答4:


Print everything starting from the first occurrence of the pattern, reverse the file, print everything starting from the first occurrence of the pattern, then reverse the result:

awk "/Lecture/,0" file.txt | tac | awk "/Lecture/,0" | tac


来源:https://stackoverflow.com/questions/62493807/how-to-delete-all-lines-before-the-first-and-after-the-last-occurrence-of-a-stri

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