Grupo de captura de expresiones regulares de bash

22

Estoy tratando de hacer coincidir múltiples valores alfanuméricos (este número podría variar) de una cadena y guardarlos en una matriz de grupo de captura bash. Sin embargo, solo estoy obteniendo el primer partido:

mystring1='<link rel="self" href="/unix//api/clouds/1/instances/1BBBBBB"/> dsf <link rel="self" href="/unix//api/clouds/1/instances/2AAAAAAA"/>'

regex='/instances/([A-Z0-9]+)'

[[ $mystring1 =~ $regex ]]

echo ${BASH_REMATCH[1]}
1BBBBBB

echo ${BASH_REMATCH[2]}

Como puede ver, coincide con el primer valor que estoy buscando, pero no con el segundo.

Arthur Lyssenko
fuente
1
¿Estaría contento con recorrer en bucle la salida de echo "$mystring1" | grep -oE '/instances/([A-Z0-9]+)'?
Jeff Schaller
44
Probablemente valga la pena mencionar el famoso No puedes analizar HTML con la publicación de expresiones regulares .
Trauma digital

Respuestas:

22

Es una pena que no puedas hacer correspondencias globales en bash. Puedes hacerlo:

global_rematch() { 
    local s=$1 regex=$2 
    while [[ $s =~ $regex ]]; do 
        echo "${BASH_REMATCH[1]}"
        s=${s#*"${BASH_REMATCH[1]}"}
    done
}
global_rematch "$mystring1" "$regex" 
1BBBBBB
2AAAAAAA

Esto funciona cortando el prefijo coincidente de la cadena para que la siguiente parte pueda coincidir. Destruye la cadena, pero en la función es una variable local, a quién le importa.

De hecho, usaría esa función para llenar una matriz:

$ mapfile -t matches < <( global_rematch "$mystring1" "$regex" )
$ printf "%s\n" "${matches[@]}"
1BBBBBB
2AAAAAAA
Glenn Jackman
fuente
gracias, esto parece una solución viable, solo el problema es que mapfile no existe en bash 3.2 ...
Arthur Lyssenko
1
Ver mywiki.wooledge.org/BashFAQ/001 para alternativas
glenn jackman
6

Para obtener el segundo valor de la matriz, debe tener un segundo conjunto de paréntesis en la expresión regular:

mystring1='<link rel="self" href="/unix//api/clouds/1/instances/1BBBBBB"/> dsf <link rel="self" href="/unix//api/clouds/1/instances/2AAAAAAA"/>'

regex='/instances/([A-Z0-9]+).*/instances/([A-Z0-9]+)'

[[ $mystring1 =~ $regex ]]

$ echo ${BASH_REMATCH[1]}
1BBBBBB
$ echo ${BASH_REMATCH[2]}
2AAAAAAA
Jeff Schaller
fuente
Gracias, sin embargo, estoy buscando un número desconocido de posibles coincidencias.
Arthur Lyssenko
1
Elevé tu Q porque también esperaba que hubiera varias coincidencias en la matriz, pero no parece que lo hagan, a menos que realmente tengas varios conjuntos de paréntesis.
Jeff Schaller