Printing the last window with sed

I have a log to process that is roughly structured like this:

...
...
sentinel
marker
...
marker
...
sentinel
marker
...

      

I want everything between marker

and the next sentinel

, and I want the last such "window". The following is done:

sed -e "1{h;d} ; 2,109{H;d} ; 110{H;g} ; /sentinel/h ; \${g;q} ; N ; D" file.log

      

Here 110 is a rough (but consistent within a couple of lines) estimate of the space between marker

for this log, but I would have to recalculate that estimate for other logs, which is annoying.

I am wondering if there is a more elegant way to achieve this with sed

, i.e. automatically return the last window between marker

and sentinel

(I also agree with the answer, which shows why you can "t do this in sed

).

Thank.

PS I know this can be done in any number of languages, but I would like to use muscles sed

.

+3


source to share


2 answers


This might work for you (GNU sed):

sed '/marker/,/sentinel/{/marker/h;//!H};$!d;x' file

      

Hide the lines between marker

and sentinel

in the hold space (overwriting the old one with the new one) and at the end of the file print whatever is left in the hold.

EDIT:



The solution above satisfies the pairs marker

and sentinel

. If any of these are likely to be missing, use:

 sed '/marker/,/sentinel/H;$!d;x;s/.*\(marker.*sentinel\).*/\1/p;d' file

      

This keeps all pairs marker/sentinel

in hold space, and at the end of the file deletes all but the last complete pair.

+2


source


If you know there are no empty lines in the file, you can do:

sed -e '/^marker$/i\
\
' -e '/^sentinel$/a\
\
' input | awk '/sentinel/{l=$0}END{print l}' RS=

      

(Not sure if I would call it elegant: basically you insert blank lines between records and let awk RS do the heavy lifting. Unless you can guarantee there are no blank lines, before / after processing the data to ensure that:



sed 's/^/x/' input | sed -e '/^xmarker$/i\
\
' -e '/^sentinel$/a\
\
' | awk '/sentinel/{l=$0}END{print l}' RS= | sed 's/^x//'

      

(Of course, you could have avoided additional sed by wrapping them in existing sed and awk, but the idea is (I think) clearer.)

0


source







All Articles