Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm having a program that intermingles data segments into log output:

log message
log message
----BEGIN INLINE DATA----
data
data
data
-----END INLINE DATA-----
log messge

I'm looking for something like,

awk '/-BEGIN INLINE DATA-/,/-END INLINE DATA-/'

but it should only print the last data segment, and without the surrounding 'tags'.

share|improve this question
    
If the data lines are complex please expand your example to show one of them. –  slm Oct 20 '13 at 3:16
    
@awkward_grep I'm guessing your choice of user name was influenced by this? :) –  Joseph R. Oct 20 '13 at 19:43
add comment

5 Answers

With awk, start accumulating data after a start marker and stop when you encounter an end marker. Reinitialize the data accumulator if you encounter a new start marker.

awk '
    /-BEGIN INLINE DATA-/ {acc = ""; storing = 1}
    /-END INLINE DATA-/ {storing = 0}
    storing {data += $0}
    END {print data}
'
share|improve this answer
add comment

You can pipe two seds like this:

<your program> | tac | sed '1,/END INLINE DATA/d' | sed '/BEGIN INLINE DATA/,$d' | tac
share|improve this answer
    
but this will only print one line –  awkward_grep Oct 20 '13 at 3:07
    
Sorry, I misread. Just omit the tail at the end and it should pick the first data block. –  Karol Oct 20 '13 at 3:20
    
Duh, you want the last block. Just use tac before and after the seds. –  Karol Oct 20 '13 at 3:27
add comment
tac log.txt | sed '1,/END INLINE DATA/d' | sed '/BEGIN INLINE DATA/,$d' | tac

seems to do the job

share|improve this answer
    
I'm guessing this is taken from Karol's answer. If the answer has helped you, the correct way of indicating this is to mark it as accepted (use the tick box below the voting markers next to the question). Please note that Stack Exchange format is different from conventional forums. –  Joseph R. Oct 20 '13 at 19:38
add comment

You can use this command to get what you want:

$ sed -n '/BEGIN/,/END/p' < data.txt | sed '1d;$d' | tail -1
data

Details

The sed command prints all the lines (inclusive) between the BEGIN and END lines. The 2nd sed command chops off the first and last lines, while the tail command returns the last line.

Alternatives

You could easily use your awk line as well:

$ awk '/-BEGIN INLINE DATA-/,/-END INLINE DATA-/'  data.txt | sed '1d;$d' | tail -1
data
share|improve this answer
    
But the OP doesn't want the last line (s)he wants the last data block. –  Joseph R. Oct 20 '13 at 19:38
    
@JosephR. - yeah that's why I asked him/her to add an example of the "data" segment/line/whatever it is so we could make sure our solutions were apt. –  slm Oct 20 '13 at 19:50
add comment

Here's a rather unorthodox way of doing it in Perl:

perl -ne '
  BEGIN{ $/="----BEGIN INLINE DATA----\n" } # Set input record separator

  $payload= s/----END INLINE DATA----.*\z//rs; # Remove end marker and messages

  END{ print $payload } # Print the last payload

' file

This needs Perl v5.14 or higher. If you're stuck with an older version of Perl you'll need an extra line:

perl -ne '
  BEGIN{ $/="----BEGIN INLINE DATA----\n" } # Set input record separator

  $payload= $_; # Copy current line into $payload
  $payload=~ s/----END INLINE DATA----.*\z//s; # Remove end marker and messages

  END{ print $payload } # Print the last payload

' file
share|improve this answer
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.