O padrão *: corresponderá a todos até o último : . Para parar no próximo : , você precisa de *?: . Por exemplo:
% grep -Poz '^:MENU1\K[\w\W]*?:' data.txt
0. public
1. admin
2. webmail
:
Você pode remover a primeira linha combinando a nova linha antes de seu \K . Por exemplo:
% grep -Poz '^:MENU1\n\K[\w\W]*?:' data.txt
0. public
1. admin
2. webmail
:
Para comer a linha vazia e o : , você pode combinar e descartar esse texto. Por exemplo:
% grep -Poz '^:MENU1\n\K[\w\W]*?(?=\n+:)' data.txt
0. public
1. admin
2. webmail
Em seguida, podemos simplificar sua classe de caracteres, para corresponder a qualquer coisa, exceto : :
% grep -Poz '^:MENU1\n\K[^:]*?(?=\n+:)' data.txt
0. public
1. admin
2. webmail
E finalmente podemos reescrever a parte inicial da partida:
% grep -Poz '(?<=:MENU1\n)[^:]*?(?=\n+:)' data.txt
0. public
1. admin
2. webmail
Isso é semelhante ao que @terdon criou, mas isso cuida das linhas em branco sem outra chamada para o grep.
Este regex final faz uso de asserções look-around . A (?<=pattern) é uma asserção look-behind que permite corresponder o pattern , mas não incluí-lo como parte da saída. A (?=pattern) é uma asserção de look-ahead e nos permite corresponder no padrão à direita sem incluí-lo na saída.