How to get lines from the last match to the end of file?

邮差的信 提交于 2021-02-19 06:39:10

问题


Need to print lines after the last match to the end of file. The number of matches could be anything and not definite. I have some text as shown below.

MARKER
aaa
bbb
ccc
MARKER
ddd
eee
fff
MARKER
ggg
hhh
iii
MARKER
jjj
kkk
lll

Output desired is

jjj
kkk
lll

Do I use awk with RS and FS to get the desired output?


回答1:


You can actually do it with awk (gawk) without using any pipe.

$ awk -v RS='(^|\n)MARKER\n' 'END{printf "%s", $0}' file
jjj
kkk
lll

Explanations:

  • You define your record separator as (^|\n)MARKER\n via RS='(^|\n)MARKER\n', by default it is the EOL char
  • 'END{printf "%s", $0}' => at the end of the file, you print the whole line, as RS is set at (^|\n)MARKER\n, $0 will include all the lines until EOF.


Another option is to use grep (GNU):
$ grep -zoP '(?<=MARKER\n)(?:(?!MARKER)[^\0])+\Z' file
jjj
kkk
lll

Explanations:

  • -z to use the ASCII NUL character as delimiter
  • -o to print only the matching
  • -P to activate the perl mode
  • PCRE regex: (?<=MARKER\n)(?:(?!MARKER)[^\0])+\Z explained here https://regex101.com/r/RpQBUV/2/


Last but not least, the following sed approach can also been used:
sed -n '/^MARKER$/{n;h;b};H;${x;p}' file
jjj
kkk
lll

Explanations:

  • n jump to next line
  • h replace the hold space with the current line
  • H do the same but instead of replacing, append
  • ${x;p} at the end of the file exchange (x) hold space and pattern space and print (p)

that can be turned into:

tac file |  sed -n '/^MARKER$/q;p' | tac

if we use tac.




回答2:


Could you please try following.

tac file | awk '/MARKER/{print val;exit} {val=(val?val ORS:"")$0}' | tac

Benefit of this approach will be awk will just read last block of the Input_file(which will be actually first block for awk after tac prints it reverse)and exit after that.

Explanation:

tac file |                      ##Printing Input_file in reverse order.
awk '
  /MARKER/{                     ##Searching for a string MARKER in a line of Input_file.
    print val                   ##Printing variable val here. Because we need last occurrence of string MARKER,which has become first instance after reversing the Input_file.
    exit                        ##Using exit to exit from awk program itself.
  }
  {
    val=(val?val ORS:"")$0      ##Creating variable named val whose value will be keep appending to its own value with a new line to get values before string MARKER as per OP question.
  }
' |                             ##Sending output of awk command to tac again to make it in its actual form, since tac prints it in reverse order. 
tac                             ##Using tac to make it in correct order(lines were reversed because of previous tac).



回答3:


You can try Perl as well

$ perl -0777 -ne ' /.*MARKER(.*)/s and print $1 ' input.txt

jjj
kkk
lll

$



回答4:


This might work for you (GNU sed):

sed -nz 's/.*MARKER.//p' file

This uses greed to delete all lines upto and including the last occurrence of MARKER.




回答5:


Simplest to remember:

tac fun.log | sed "/MARKER/Q" | tac


来源:https://stackoverflow.com/questions/56334150/how-to-get-lines-from-the-last-match-to-the-end-of-file

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