26

I'm trying to match multiple alphanumeric values (this number could vary) from a string and save them to a bash capture group array. However, I'm only getting the first match:

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

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

[[ $mystring1 =~ $regex ]]

echo ${BASH_REMATCH[1]}
1BBBBBB

echo ${BASH_REMATCH[2]}

As you can see- it matches the first value I'm looking for, but not the second.

29

It's a shame that you can't do global matching in bash. You can do this:

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

This works by chopping the matched prefix off the string so the next part can be matched. It destroys the string, but in the function it's a local variable, so who cares.

I would actually use that function to populate an array:

$ mapfile -t matches < <( global_rematch "$mystring1" "$regex" )
$ printf "%s\n" "${matches[@]}"
1BBBBBB
2AAAAAAA
| improve this answer | |
  • thanks- this looks like a viable solution- only issue is mapfile not existing in bash 3.2... – Arthur Lyssenko Dec 22 '15 at 22:19
  • 1
    See mywiki.wooledge.org/BashFAQ/001 for alternatives – glenn jackman Dec 23 '15 at 0:30
  • @glennjackman What was I thinking?, sorry! I'll remove the comments. – Isaac Apr 14 at 21:09
9

To get the second array value, you need to have a second set of parentheses in the regex:

mystring1='<link rel="self" href="/api/clouds/1/instances/1BBBBBB"/> dsf <link rel="self" href="/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
| improve this answer | |
  • Thanks, hoever I'm looking to match an unknown number of possible matches. – Arthur Lyssenko Dec 22 '15 at 21:36
  • 1
    I upvoted your Q because I also expected multiple matches to go into the array, but they don't seem to, unless you actually have multiple sets of parentheses. – Jeff Schaller Dec 22 '15 at 21:40
0

Python implementation :

def getall(mysentence):
    regex = re.compile(r'.*?/instances/([0-9A-Z]+)')
    result = regex.findall(mysentence)
    return result

print(getall('<link rel="self" href="/api/clouds/1/instances/1BBBBBB"/> dsf <link rel="self" href="/api/clouds/1/instances/2AAAAAAA"/>'))
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.