1

I have a string of following format to be matched

./foo/baz/bar/filename.c

My regex looks like this

  regex=$'^(\./)?([a-zA-Z0-9_-]+/)+([a-zA-Z0-9_-]+\.[a-z]+)$'

The test looks like this

[[ $search =~ $regex ]]

In this thread there is an interesting code code example example by user glenn jackman in order to capture repeated occurences of the same capturing-group

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" 

But in the regex there, there is only one capturing group. My case here is a little different.

My $regex tries to extract multiple occurences of one capturing-group. But that capturing group is treated lazily (or what is the correct term here? global matching ?) and it only outputs its' first occurence. The others are discarded.

$ printf "%s\n" "${BASH_REMATCH[@]}"
./foo/baz/bar/filename.c
./
bar/
filename.c

All occurences are only put out when I add an additional pair of parentheses, but that's not the result what I want.

regex=$'^(\./)?(([a-zA-Z0-9_-]+/)+)([a-zA-Z0-9_-]+\.[a-z]+)$'

The result is

echo "${BASH_REMATCH[2]}"
foo/baz/bar/

Is there a way to apply the code example above or another solution such that all repeated occurences are stored in BASH_REMATCH by an own index instead ?

Such that the indices would be something like this:

echo "${BASH_REMATCH[2]}"
./foo/baz/bar/filename.c
echo "${BASH_REMATCH[1]}"
./
echo "${BASH_REMATCH[2]}"
foo/
echo "${BASH_REMATCH[3]}"
baz/
echo "${BASH_REMATCH[4]}"
bar/
echo "${BASH_REMATCH[5]}"
filename.c

Maybe I just have to run two pattern matchings, one with only one capturing group. As workaround.

4
  • Glenn's code won't work here since you have the (\./)? in your regex because that will be removed by the first run of the while in the global_rematch function, but because of the ?, the string will keep on matching for ever. This feels like an XY problem though. Can you explain what you will be doing with this array downstream in your program? We may be able to give a different approach. If all you want is to separate the path into each component part, there are better ways than regular expression matching. – terdon Jun 12 at 11:33
  • Actually, is this question maybe obsolete now that you have gotten an answer to your newer one? – terdon Jun 12 at 12:58
  • Is this still an issue? Or should the question be closed/deleted? – Kusalananda Jun 14 at 9:04
  • It's still an issue if there is a rather quick solution. Otherwise I'll have to break the problem of matching the parts I am intersting in in sub-problems by parameter-expansion and pattern-matching to reduce the string step by step by those parts. Would you know a faster, more convenient way, where foo/baz/bar each get an own index, like ${BASH_REMATCH[3]} => foo/, ${BASH_REMATCH[4]} => baz/, ${BASH_REMATCH[5]} => bar/ – von spotz Jun 15 at 10:12

Your Answer

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

Browse other questions tagged or ask your own question.