extract lines from bottom until regex match
This feels a bit silly, but:
$ tac file.txt |sed -e '/^virt-top/q' |tac
virt-top time 11:25:17 Host foo.example.com x86_64 32/32CPU 1200MHz 65501MB
ID S RDRQ WRRQ RXBY TXBY %CPU %MEM TIME NAME
1 R 0 0 0 0 0.6 12.0 96:02:53 instance-0000036f
2 R 0 0 0 0 0.2 12.0 95:44:08 instance-00000372
GNU tac
reverses the file (many non-GNU systems have tail -r
instead), the sed
picks lines until the first that starts with virt-top
. You can add sed 1,2d
or tail -n +3
to remove the headers.
Or in awk:
$ awk '/^virt-top/ { a = "" } { a = a $0 ORS } END {printf "%s", a}' file.txt
virt-top time 11:25:17 Host foo.example.com x86_64 32/32CPU 1200MHz 65501MB
ID S RDRQ WRRQ RXBY TXBY %CPU %MEM TIME NAME
1 R 0 0 0 0 0.6 12.0 96:02:53 instance-0000036f
2 R 0 0 0 0 0.2 12.0 95:44:08 instance-00000372
It just collects all the lines to a variable, and clears that variable on a line starting with virt-top
.
If the file is very large, the tac
+sed
solution is bound to be faster since it only needs to read the tail end of the file while the awk
solution reads the full file from the top.
With ed
you can regex-search upward using ?pattern?
in place of the usual /pattern/
(which searches from above the current position). So for example:
$ printf '%s\n' '?ID?+1,$p' q | ed -s file.txt
1 R 0 0 0 0 0.6 12.0 96:02:53 instance-0000036f
2 R 0 0 0 0 0.2 12.0 95:44:08 instance-00000372
If your input has a fixed number of blocks you could also do something like:
awk '/^virt-top/ && ++n == 2, 0' <your-file
To output the lines from the 2nd occurrence of virt-top
to the end of the file (0 meaning false, means the end of that first,last range is never found).