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.

Arthur Lyssenko
la source
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
glenn jackman
la source
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
Jeff Schaller
la source
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