Existe uma maneira de limitar o intervalo do padrão de intervalo no awk?

1

Estou tentando usar o padrão awk range para encontrar todas as declarações select do SQL em um grupo de arquivos, inspirados por esta resposta do stackoverflow .

Do manual awk :

The pattern1, pattern2 form of an expression is called a range pattern. It matches all input records starting with a record that matches pattern1, and continuing until a record that matches pattern2, inclusive.

Minha tentativa inicial foi

awk '/select/,/from/' *

onde * neste caso representa apenas um grande número de arquivos variados.

Isso retornou vários resultados falsos em HTML select tags, então refinei meu comando para

awk '/[^<]select[^>]/,/from/' *

que parece ter eliminado a maioria desses hits.

No entanto, ainda recebo alguns resultados falsos de ocorrências da palavra "select" em um comentário, e esses hits produzem muitas linhas de ruído antes de chegarem a um "from" ou ao final do arquivo. O que eu gostaria é que o padrão de intervalo não registre uma correspondência se houver mais do que, digamos, 10 linhas entre o "select" e o "from".

Minha pergunta é: posso fazer com que o padrão de intervalo não corresponda se o número de linhas entre a correspondência de pattern1 e a correspondência de pattern2 exceder um determinado limite e, em caso afirmativo, como?

    
por Anders Rabo Thorbeck 30.04.2015 / 13:08

2 respostas

0

Você pode expandir a condição /pattern1/,/pattern2/ o quanto quiser, adicionando um bloco {} após ser executado quando isso ocorrer:

Veja, por exemplo, como imprimimos esses números entre 50 e 70, mas apenas as 5 primeiras correspondências de cada bloco:

$ seq 200 | awk '/50/,/70/ {if ($0~/50/) {c=0}; if (c++ <= 5) print}'
50
51
52
53
54
55
150
151
152
153
154
155

No seu caso, você pode querer dizer algo assim, que imprimirá as primeiras 10 linhas que foram correspondidas.

awk '/[^<]select[^>]/,/from/ {if (c++ <= 10) print}' *

Uma solução mais complexa consistiria em armazenar toda essa saída e depois imprimi-la no bloco END . Dessa forma, você pode controlar o bloco em vez de apenas uma linha específica. Eu faria isso armazenando os dados em um array, etc.

    
por 30.04.2015 / 13:32
0

Os padrões de intervalo são úteis, mas não são flexíveis. Em vez de usá-los, mantenha o estado entre ou não em uma variável. O script awk /select/,/from/ é equivalente a

/select/ {printing = 1}
printing {print}
/from/ {printing = 0}

Se você quiser limitar o intervalo a um número de linhas, mantenha um contador de linhas vistas e acumule a saída até decidir se deseja exibi-la.

/select/ {select_text = $0; select_line_count = 1;}
select_line_count {select_text = select_text "\n" $0}
/from/ {if (select_line_count <= 10) {print select_text; print}
        select_line_count = 0}

Você provavelmente desejará refinar o padrão, por exemplo, para exigir que select esteja no início da linha, exceto para espaço em branco, e seja seguido por espaços em branco: /^[\t ]*select($|[\t ])/

    
por 01.05.2015 / 01:06

Tags