Me gustaría recorrer cada patrón encontrado y tener acceso a los diferentes grupos de captura dentro del ciclo, posiblemente con grep
o awk
(Me gustaría quedarme con ellos si es posible para evitar aprender un tercero, pero si es realmente necesario, ¡aprenderé otro!)
Hace 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 muestra:
blah12687hello=123
nothingthatmatches
blah3211hello=123456
blah15butnottheotherpattern
Con el ciclo mencionado anteriormente, debería generar:
blah12687hello=123
12687
<it should run the command dosomethingwith 123>
blah3211hello=123456
3211
<it should run the command dosomethingwith 123456>
Respuesta aceptada:
El bash
Shell por sí mismo proporciona una manera de hacer que el proceso de coincidencia de expresiones regulares de los grupos capturados sea convenientemente necesario.
El =~
operador dentro de una expresión de prueba de corchetes dobles, [[
con la cadena de coincidencia en el lado izquierdo del operador y la expresión regular como el operando derecho.
if [[ "$str" =~ $re ]]; then
Si la expresión coincide con la cadena, la parte coincidente de la cadena se almacena en el BASH_REMATCH
matriz que se puede recorrer para acceder a los grupos capturados individuales. El estado de salida es si la expresión regular coincide,
1
si no es así, y 2
si la expresión no es válida.
En lo que respecta a su ejemplo, suponiendo que tiene las líneas de entrada almacenadas en una matriz y las palabras blah
y hello
son patrones fijos
#!/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 puede ver en el código anterior, una vez que hacemos coincidir la expresión regular para que sea verdadera, podemos recorrer el BASH_REMATCH
matriz para imprimir cada uno de los grupos capturados. El resultado general del script sería 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 puede ver el BASH_REMATCH[0]
siempre contiene la parte de la cadena que coincidió correctamente con la expresión regular, y se puede acceder a los grupos capturados individuales desde el índice 1
adelante. Puede escribir una lógica personalizada para procesar cada uno de los grupos capturados, que es lo que originalmente pretendía hacer.
Si está interesado en leer una entrada de archivo, simplemente use un while
bucle con redirección de entrada en el archivo a procesar
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