2

I need to match a string $str that contains any of

foo{77..93}

and capture the above substring in a variable. So far I've got:

str=/random/string/containing/abc-foo78_efg/ # for example
if [[ $str =~ (foo[7-9][0-9]) ]]; then
    id=${BASH_REMATCH[1]}
fi
echo $id # gives foo78

but this also captures ids outside of the target range (e.g. foo95). Is there a way to restrict the regex to an exact integer range? (tried foo[77-93] but that doesn't work.

Thanks

2 Answers 2

6

If you want to use a regex, you're going to have to make it slightly more complex:

if [[ $str =~ foo(7[7-9]|8[0-9]|9[0-3]) ]]; then
    id=${BASH_REMATCH[0]}
fi

Note that I have removed the capture group around the whole pattern and am now using the 0th element of the match array.

As an aside, for maximum compatibility with older versions of bash, I would recommend assigning the pattern to a variable and using in the test like this:

re='foo(7[7-9]|8[0-9]|9[0-3])'
if [[ $str =~ $re ]]; then
    id=${BASH_REMATCH[0]}
fi

An alternative to using a regex would be to use an arithmetic context, like this:

if (( "${str#foo}" >= 77 && "${str#foo}" <= 93 )); then
    id=$str
fi

This strips the "foo" part from the start of the variable so that the integer part can be compared numerically.

Sign up to request clarification or add additional context in comments.

2 Comments

That's great Tom thanks. However $str is a string containing fooXX. how would that change your answer?
It doesn't affect the regex-based method. To use the other method, you'd have to extract the substring using something like num=${str#*foo}; num=${num//[^0-9]/}. Personally I'd just go with the first method in that case.
1

Sure is easy to do with Perl:

$ echo foo{1..100} | tr ' ' '\n' | perl -lne 'print $_ if m/foo(\d+)/ and $1>=77 and $1<=93'
foo77
foo78
foo79
foo80
foo81
foo82
foo83
foo84
foo85
foo86
foo87
foo88
foo89
foo90
foo91
foo92
foo93

Or awk even:

$ echo foo{1..100} | tr ' ' '\n' | awk -F 'foo' '$2>=77 && $2<=93
 {print}'
foo77
foo78
foo79
foo80
foo81
foo82
foo83
foo84
foo85
foo86
foo87
foo88
foo89
foo90
foo91
foo92
foo93

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.