Bash Regex – How to Handle Multiple Matches in Bash Regular Expressions

bashregular expression

I have a nice little bash script which parses a message for a regular expression and does something with the capture groups:

regex='\((Closes|Resolves):\s([0-9]+)\)'
msg='Fixed a problem (Closes: 1234), (Resolves: 5678)'

if [[ $msg =~ $regex ]] ; then
  action="${BASH_REMATCH[1]}"
  issue="${BASH_REMATCH[2]}"
  do_something $action $issue
fi

This works well for the first match, but if there are multiple matches msg, later matches are ignored. Is there a way for me to loop through each match or is it time to start thinking of python or perl?

Best Answer

It's not explicitly supported by built-in bash syntax, but it can be easily achieved with a little variable substitution and some recursion.

function do_something {
  echo $1 $2
}

function handlematches {
  regex='\((Closes|Resolves):\s([0-9]+)\)'
  msg=$1

  if [[ $msg =~ $regex ]] ; then
    action="${BASH_REMATCH[1]}"
    issue="${BASH_REMATCH[2]}"
    do_something "$action" "$issue"

    # Remove the first regex match and try again
    handlematches "${msg/${BASH_REMATCH[0]}/}"
  fi
}

message='Fixed a problem (Closes: 1234), (Resolves: 5678)'
handlematches "$message"

Output:

Closes 1234
Resolves 5678
Related Question