grep solução de expressão regular (ganancioso não funciona)

4

Eu tenho o seguinte texto no arquivo data.txt

:MENU1
0. public
1. admin
2. webmail

:SYNTAX
! opt1, ... :

:ERROR1
Error #1, blah... blah.. blah...
Please do ...

:ERROR2
Error #2 ...

e quero usar uma expressão regular (sintaxe PERL) para extrair a parte de :MENU1 para a próxima primeira : , mas descartando MENU1 e a última : do resultado.

Tentei várias regexs mas na solução mais próxima que consegui Eu não posso colocar a opção 'gananciosa' para funcionar e não posso descartar o último ":"

grep -Poz "^:MENU1\K[\w\W]*:"

isso funciona com o grep ...
mas traz todo o texto até o último ":" ...
Eu quero apenas até o próximo primeiro ":" depois de :MENU1 :

0. public
1. admin
2. webmail
 

(observe a linha final em branco)

    
por ZEE 30.09.2015 / 19:46

3 respostas

4

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.

    
por 30.09.2015 / 20:15
2

Que tal: grep -Poz "^:MENU1\K[^:]*" ?

    
por 30.09.2015 / 19:58
2

@ A solução de Herbert é provavelmente a mais simples, mas você também pode usar lookarounds:

$ grep -Poz '(?<=:MENU1\n)[^:]*' file 
0. public
1. admin
2. webmail
  
    
por 30.09.2015 / 20:18