Groupe de capture de regex bash


22

J'essaie de faire correspondre plusieurs valeurs alphanumériques (ce nombre peut varier) à partir d'une chaîne et de les enregistrer dans un tableau de groupe de capture bash. Cependant, je n'obtiens que le premier match:

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]}

Comme vous pouvez le voir, cela correspond à la première valeur que je recherche, mais pas à la seconde.


1
Seriez-vous content de boucler sur la sortie de echo "$mystring1" | grep -oE '/instances/([A-Z0-9]+)'?
Jeff Schaller

4
Il vaut probablement la peine de mentionner le célèbre You can not parse HTML with regex post.
Digital Trauma

Réponses:


22

C'est dommage que vous ne puissiez pas faire de correspondance globale dans bash. Tu peux le faire:

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

Cela fonctionne en coupant le préfixe correspondant de la chaîne afin que la partie suivante puisse être mise en correspondance. Il détruit la chaîne, mais dans la fonction, c'est une variable locale, alors peu importe.

J'utiliserais en fait cette fonction pour remplir un tableau:

$ mapfile -t matches < <( global_rematch "$mystring1" "$regex" )
$ printf "%s\n" "${matches[@]}"
1BBBBBB
2AAAAAAA

merci - cela ressemble à une solution viable - seul le problème est que le fichier map n'existe pas dans bash 3.2 ...
Arthur Lyssenko

1
Voir mywiki.wooledge.org/BashFAQ/001 pour les alternatives
glenn jackman

6

Pour obtenir la deuxième valeur du tableau, vous devez avoir un deuxième ensemble de parenthèses dans l'expression régulière:

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

Merci, mais je cherche à faire correspondre un nombre inconnu de correspondances possibles.
Arthur Lyssenko

1
J'ai voté pour votre Q parce que je m'attendais également à ce que plusieurs correspondances entrent dans le tableau, mais elles ne semblent pas le faire, sauf si vous avez réellement plusieurs jeux de parenthèses.
Jeff Schaller
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.