Capture grupos com awk ou grep

0

Gostaria de fazer um loop sobre cada padrão encontrado e ter acesso aos diferentes grupos de captura dentro do loop, possivelmente com grep ou awk (gostaria de continuar com eles se possível para evitar aprender um 3º, mas se for realmente necessário, vou aprender outro!)

Faz algo como:

awk-or-grep -E '(blah(.*)hello=(.*))' sampletext | while read -r l; do 
    echo $0             #1st capture group
    echo $1             #2nd catpure group
    dosomethingwith $2  #3rd capture group
done

existe?

Texto de amostra:

blah12687hello=123
nothingthatmatches
blah3211hello=123456
blah15butnottheotherpattern

Com o loop mencionado antes, ele deve produzir:

blah12687hello=123
12687
<it should run the command dosomethingwith 123>
blah3211hello=123456
3211
<it should run the command dosomethingwith 123456>
    
por Basj 04.10.2017 / 16:57

1 resposta

2

O shell bash , por si só, fornece uma maneira de fazer o processo de correspondência de expressão regular dos grupos capturados, conforme necessário.

O operador =~ dentro de uma expressão de teste de colchetes duplos, [[ com a cadeia de correspondência no lado esquerdo do operador e a expressão regular como o operando da direita.

if [[ "$str" =~ $re ]]; then

Se a expressão corresponder à string, a parte correspondente da string será armazenada na matriz BASH_REMATCH , que pode ser colocada em loop para acessar os grupos capturados individuais. O status de saída é 0 se o regexp corresponder, 1 se isso não ocorrer e 2 se a expressão for inválida.

No que diz respeito ao seu exemplo, supondo que você tenha as linhas de entrada armazenadas em uma matriz e as palavras blah e hello sejam padrões fixos

#!/usr/bin/env bash

exampleStr=('blah12687hello=123' 'nothingthatmatches' 'blah3211hello=123456' 'blah15butnottheotherpattern')

re='blah([[:digit:]]+)hello=([[:digit:]]+)'

for str in "${exampleStr[@]}"; do
    if [[ "$str" =~ $re ]]; then
       for group in "${BASH_REMATCH[@]}"; do
           printf "%s\n" "$group"
       done
    else
       printf "No match \n"
    fi
done

Como você pode ver no código acima, uma vez que correspondamos a expressão regular para ser verdade, podemos percorrer a matriz BASH_REMATCH para imprimir cada um dos grupos capturados. A saída geral do script seria algo como

blah12687hello=123     # Value of BASH_REMATCH[0]
12687                  # Value of BASH_REMATCH[1]
123                    # Value of BASH_REMATCH[2]
Regex not matches.
blah3211hello=123456
3211
123456
Regex not matches.

Como você pode ver, o BASH_REMATCH[0] sempre contém a parte da string que foi correspondida com sucesso pelo regex, e os grupos capturados individuais podem ser acessados a partir do índice 1 em diante. Você pode escrever uma lógica personalizada para processar cada grupo capturado, que é o que você originalmente pretendia fazer.

Se você estiver interessado em ler uma entrada de arquivo, use um loop while com redirecionamento de entrada no arquivo a ser processado

while IFS= read -r line; do
    if [[ "$line" =~ $re ]]; then
       for group in "${BASH_REMATCH[@]}"; do
           printf "%s\n" "$group"
       done
    else
       printf "No match \n"
    fi
done < inputFile.txt
    
por 04.10.2017 / 17:25

Tags