How to find last occurrence of pattern and print all lines following the last occurance [duplicate]

How to find last occurrence of pattern and print all lines following the last occurance [duplicate]



This question already has an answer here:



I have a file which contains multiple occurrences of pattern "====". These patterns are followed by texts. I'd like to search for the last occurrence of the "====" pattern and print all the lines after the pattern. Any ideas on how to do it in bash? Combination of grep, awk, sed or tail, etc..?


grep


awk


sed


tail



Sample file:


====

First run of script

End of first Script

====

2nd run of script

End of 2nd script

====

3rd run of script

End of 3rd script



Output of the command should look like below.


3rd run of script

End of 3rd script



This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.






Thank you @l0b0 for posting the link. Sorry for the duplicate question. I had done many searches for a possible solution and the link you provided matches my exact needs.

– user612223
Sep 9 '18 at 4:13






No problem at all; cross-site duplicates aren't a thing, and a question being duplicate doesn't mean it's bad.

– l0b0
Sep 9 '18 at 4:22






Welcome , You can vote up or accept the answer which solve your problem instead of editing your question.

– GAD3R
Sep 9 '18 at 11:20





5 Answers
5



Based on SO duplicate:


$ sed -n '/====/h;//!H;$!d;x;//p' sample.txt
====

3rd run of script

End of 3rd script

Output of the command should look like below.

3rd run of script

End of 3rd script



I started writing an explanation, but I don't actually understand some of the commands so I'll just refer to info sed.


info sed






(Let's see if I got this right) /====/h sets the hold buffer to the current line if it matches ====; //!H adds it to the hold buffer if it doesn't match ====. Those combine to clear the hold on a ==== and to store any lines in there. Then $!d deletes the current line (it's already stored in the hold) and jumps to the next, unless this was the last line. The x and p only run on the last line: x loads the hold buffer to the active buffer, and //p prints it if it contains a ====. (The // pattern means to use the previous pattern, so it's just a shorthand for /====/.)

– ilkkachu
Sep 9 '18 at 12:19



/====/h


====


//!H


====


====


$!d


x


p


x


//p


====


//


/====/






The final condition on the p means that if ==== isn't seen, this won't print anything. But this also will print the ==== line itself.

– ilkkachu
Sep 9 '18 at 12:21


p


====


====



Software tools method, more efficient for big files since it only reads the end of the file, then stops when it finds the last match:


tac sample.txt | grep -F -m1 -B 999999 '====' | head -n -1 | tac



Note: increase or reduce 999999 as needed, just so it's longer than any possible match. See also *Glenn Jackman's answer with variants for awk and sed which avoid the need for 99999. For systems with low resources, the grep method is the most efficient of the three variants.


999999


awk


sed


99999


grep



save the text in file.txt and run this command:


file.txt


awk 'p; /====/ $p' file.txt | tail -3



output:


3rd run of script

End of 3rd script






Your awk command doesn't do anything... You may as well run only tail -3 (which is obsolete - you should use tail with -n). Either way, this only works with the OP input sample, that is it only prints the last 3 lines, regardless. I guess the 3 people who mechanically upvoted here don't care about that.

– don_crissti
Sep 9 '18 at 11:46


awk


tail -3


tail


-n






With p unset, the first p is a falsy condition, and doesn't do anything. The second is the same as /====/ $0 when p gets coerced to an integer, but what in the world is the concatenation of a regex and a field (or string) supposed to be? It does seem to act like a true condition, though, so it looks like that's the same as running awk 1. Or cat.

– ilkkachu
Sep 9 '18 at 11:53


p


p


/====/ $0


p


awk 1


cat



Same concept as agc's answer, but doesn't require you to guess how many lines there might be:



with GNU sed


tac file | sed '/====/Q' | tac



or awk


tac file | awk '/====/ exit 1' | tac



The idea of the double tac is to invert the question: How to print all lines preceding the first occurrence of pattern. That is a much simpler problem.


tac



In awk, something like this:


awk


awk '/====/ t = ""; next t = t $0 "n"; END printf "%s", t; ' < sample.txt



It stores the input lines in t, and clears t when it sees ====. What ever is in there is printed at the end.


t


t


====



Note that


====


/^====$/


====


====


sed 1d



Another version that only starts storing input after the ==== separator is seen, effectively producing an empty output if the input doesn't contain the separator:


====


awk '/====/ any = 1; t = ""; next any t = t $0 "n"; END printf "%s", t; ' < sample.txt

Popular posts from this blog

𛂒𛀶,𛀽𛀑𛂀𛃧𛂓𛀙𛃆𛃑𛃷𛂟𛁡𛀢𛀟𛁤𛂽𛁕𛁪𛂟𛂯,𛁞𛂧𛀴𛁄𛁠𛁼𛂿𛀤 𛂘,𛁺𛂾𛃭𛃭𛃵𛀺,𛂣𛃍𛂖𛃶 𛀸𛃀𛂖𛁶𛁏𛁚 𛂢𛂞 𛁰𛂆𛀔,𛁸𛀽𛁓𛃋𛂇𛃧𛀧𛃣𛂐𛃇,𛂂𛃻𛃲𛁬𛃞𛀧𛃃𛀅 𛂭𛁠𛁡𛃇𛀷𛃓𛁥,𛁙𛁘𛁞𛃸𛁸𛃣𛁜,𛂛,𛃿,𛁯𛂘𛂌𛃛𛁱𛃌𛂈𛂇 𛁊𛃲,𛀕𛃴𛀜 𛀶𛂆𛀶𛃟𛂉𛀣,𛂐𛁞𛁾 𛁷𛂑𛁳𛂯𛀬𛃅,𛃶𛁼

ャフサォクコ ケウ,コ,ワ メ,ロスョノ゙,クネ,フムカヤヲニ,エコ゚ツ ウイオン゙ケワサネォキモュキォウイノンコチ゚メヌナイゥフュ,カヒウネェ ネ,ホノケ,ムュキ ッボーミュハ,チ ツス ィ メウイマヤ,゙ウチ ヅ ロ,ォジヌェ ャヌット ェ,マャ,チナエヒネソキツテ トホヲヲミーァ

How do I collapse sections of code in Visual Studio Code for Windows?