问题
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
viaRS='(^|\n)MARKER\n'
, by default it is theEOL
char 'END{printf "%s", $0}'
=> at the end of the file, you print the whole line, asRS
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 lineh
replace the hold space with the current lineH
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