Bash-Regex-Erfassungsgruppe

22

Ich versuche, mehrere alphanumerische Werte (diese Zahl kann variieren) von einer Zeichenfolge abzugleichen und sie in einem Bash-Capture-Gruppenarray zu speichern. Ich bekomme jedoch nur das erste 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]}

Wie Sie sehen, stimmt es mit dem ersten Wert überein, den ich suche, aber nicht mit dem zweiten.

Arthur Lyssenko
quelle
1
Würden Sie sich damit zufrieden geben, die Ausgabe von zu echo "$mystring1" | grep -oE '/instances/([A-Z0-9]+)'durchlaufen?
Jeff Schaller
4
Wahrscheinlich erwähnenswert das berühmte Sie können HTML nicht mit Regex- Post analysieren .
Digitales Trauma

Antworten:

22

Es ist eine Schande, dass Sie in Bash kein globales Matching durchführen können. Du kannst das:

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

Dies funktioniert, indem das übereinstimmende Präfix von der Zeichenfolge entfernt wird, damit der nächste Teil abgeglichen werden kann. Es zerstört den String, aber in der Funktion ist es eine lokale Variable, also wen interessiert das?

Ich würde diese Funktion tatsächlich verwenden, um ein Array zu füllen:

$ mapfile -t matches < <( global_rematch "$mystring1" "$regex" )
$ printf "%s\n" "${matches[@]}"
1BBBBBB
2AAAAAAA
Glenn Jackman
quelle
danke - dies scheint eine praktikable Lösung zu sein - nur das Mapfile ist in Bash 3.2 nicht vorhanden ...
Arthur Lyssenko
1
Siehe mywiki.wooledge.org/BashFAQ/001 für Alternativen
Glenn Jackman
6

Um den zweiten Array-Wert zu erhalten, benötigen Sie einen zweiten Satz von Klammern im regulären Ausdruck:

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
quelle
Danke, aber ich suche nach einer unbekannten Anzahl möglicher Übereinstimmungen.
Arthur Lyssenko
1
Ich habe Ihr Q hochgestuft, weil ich auch erwartet habe, dass mehrere Übereinstimmungen in das Array aufgenommen werden, aber es scheint, dass dies nicht der Fall ist, es sei denn, Sie haben tatsächlich mehrere Sätze von Klammern.
Jeff Schaller