C'est un peu idiot, mais :
$ 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 inverse le fichier (de nombreux systèmes non-GNU ont tail -r à la place), le sed sélectionne les lignes jusqu'à la première qui commence par virt-top . Vous pouvez ajouter sed 1,2d ou tail -n +3 pour supprimer les en-têtes.
Ou en 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
Il collecte simplement toutes les lignes d'une variable et efface cette variable sur une ligne commençant par virt-top .
Si le fichier est très volumineux, le tac +sed solution est forcément plus rapide puisqu'elle n'a besoin que de lire la fin du fichier tandis que le awk la solution lit le fichier complet à partir du haut.
Avec ed vous pouvez effectuer une recherche régulière vers le haut en utilisant ?pattern? à la place de l'habituel /pattern/ (qui recherche par dessus la position actuelle). Ainsi, par exemple :
$ 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
Si votre entrée a un nombre fixe de blocs, vous pouvez également faire quelque chose comme :
awk '/^virt-top/ && ++n == 2, 0' <your-file
Pour sortir les lignes de la 2 occurrence de virt-top à la fin du fichier (0 signifiant faux , signifie la fin de ce premier ,dernier la plage n'est jamais trouvée).