What's wrong with this bash regex comparison? [duplicate] - regex

This question already has answers here:
How can I match spaces with a regexp in Bash?
(4 answers)
Closed 5 years ago.
I saw in bash regex match string that I should compare regexes with =~.
Tried the following:
if [[ "____[9 / 101] Linking" =~ "[0-9]*" ]]; then echo "YES"; fi
And nothing is printed...
Tried without the quotes:
if [[ "____[9 / 101] Linking" =~ [0-9]* ]]; then echo "YES"; fi
And it works fine. But what to do if my regex contains white spaces (quotes required)?

Put your regex in a variable. You are free to use quotes when defining the variable:
$ re="[0-9]*" ; [[ "____[9 / 101] Linking" =~ $re ]] && echo "YES"
YES
$ re="9 /" ; [[ "____[9 / 101] Linking" =~ $re ]] && echo "YES"
YES
Since the reference to $re inside [[...]] is unquoted, the value of $re is treated as a regex. Anything on the right-side of =~ that is quoted, however, will be treated as a literal string.
Notes
In regular expressions, as opposed to globs, * means zero or more of the preceding. Thus [0-9]* is considered a match even if zero characters are matching:
$ re="[0-9]*" ; [[ "____[a / bcd] Linking" =~ $re ]] && echo "YES"
YES
$ re="[0-9]" ; [[ "____[a / bcd] Linking" =~ $re ]] && echo "YES"
$
If you want to match one or more digits, use [0-9]+.

Precede the whitespace with a \:
if [[ "____[9 / 101] Linking" =~ [0-9]*\ /\ [0-9]* ]]; then echo "YES"; fi

Related

Match a single character in a Bash regular expression

For some reason, the following regular expression match doesn't seem to be working.
string="#Hello world";
[[ "$string" =~ 'ello' ]] && echo "matches";
[[ "$string" =~ 'el.o' ]] && echo "matches";
The first command succeeds (as expected), but the second one does not.
Shouldn't that period be treated by the regular expression as a single character?
Quoting the period causes it to be treated as a literal character, not a regular-expression metacharacter. Best practice if you want to quote the entire regular expression is to do so in a variable, where regular expression matching rules aren't in effect, then expand the parameter unquoted (which is safe to do inside [[ ... ]]).
regex='el.o'
[[ "$string" =~ $regex ]] && echo "matches"
string="#Hello world";
[[ "$string" =~ ello ]] && echo "matches";
[[ "$string" =~ el.o ]] && echo "matches";
Test
$ string="hh elxo fj"
$ [[ "$string" =~ el.o ]] && echo "matches";
matches

Bash regexp in if statement doesn't work [duplicate]

This question already has answers here:
How to match digits in regex in bash script
(2 answers)
Closed 6 years ago.
I'm trying to play with regular expressions in bash but i can't understand why this follow scenario doesn't work :
Regexp:
REGEXP="^(test\/)(([a-zA-Z]+)\-)+(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$"
String:
STRING="test/test-ods-1.10.1"
Test:
if [[ "$STRING" =~ $REGEXP ]]
then
echo "match!"
else
echo "don't match"
fi
Normally in this scenario I should receive a "match" but it's always returning a "doesn't match".
\d is not defined in bash regexps. Replace them with [0-9] and it'll work :
$ [[ "test/test-1.10.1" =~ ^(test\/)(([a-zA-Z]+)\-)+(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$ ]]; echo $?
1
$ [[ "test/test-1.10.1" =~ ^(test\/)(([a-zA-Z]+)\-)+(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)\.(0|[1-9][0-9]*)$ ]]; echo $?
0
No shorthand classes are defined in POSIX, and GNU extensions only bring a few of them, \w, \W, \s and \S according to regular-expressions.info.

Why does this regexp matches to almost everything?

I cant really explain but check out the following:
name=$1
pat="\b[0-9a-zA-Z_]+\b"
if [[ $name =~ $pat ]]; then
echo "$name is ok as user name"
else
echo "$name is not ok as user name"
exit 1
fi
Test run:
./script test_user+
test_user+ is ok as user name
The username with a + sign should not match that regexp.
First of all:
\b is a PCRE extension; it isn't available in ERE, which the =~
operator in bash's [[ ]] syntax uses.
(From Bash regex match with word boundary)
Second, you don't want word boundaries (\b) if you wish to force the entire string to match. You want to match the start (^) and end ($):
pat="^[0-9a-zA-Z_]+\$"
if you dont want word bondry (guessed as you are trying username match) please use
^[0-9a-zA-Z_]+$
Contrary to the OP's experience and other answer it seems \b is supported on Ubuntu 14.04, bash 4.3.11 as word boundary. Here is a sample:
re='\bb[0-9]+\b'
[[ 'b123' =~ $re ]] && echo "matched" || echo "nope"
matched
[[ 'b123_' =~ $re ]] && echo "matched" || echo "nope"
nope
Even \< and \> also work fine as word boundaries:
re='\<b[0-9]+\>'
[[ 'b123' =~ $re ]] && echo "matched" || echo "nope"
matched
[[ 'b123_' =~ $re ]] && echo "matched" || echo "nope"
nope
However support of \b is specific to certain OS only. e.g. on OSX following works as word boundary:
[[ 'b123' =~ [[:\<:]]b[0-9]+[[:\>:]] ]] && echo "matched" || echo "nope"
matched
[[ 'b123_' =~ [[:\<:]]b[0-9]+[[:\>:]] ]] && echo "matched" || echo "nope"
nope

Regex match in null bash string

In bash shell
testvar=
echo $testvar
[[ $testvar =~ ^M* ]] && echo "foo"
foo
Isn't the regex pattern matching strings starting with 'M', followed by anything?
NO * means 0 or more so the empty string will be matched, add a mandatory M or use the + instead of * and it will do what you want.
Your test should look like:.
[[ $testvar =~ ^MM* ]] && echo "foo"
or
[[ $testvar =~ ^M+ ]] && echo "foo"
To match a string starting with M you have two options:
[[ $testvar = M* ]] # use glob pattern matching
or
[[ $testvar =~ ^M ]] # use a regular expression
The key problem with your attempt is that you've put the * directly after the M, which matches zero or more Ms at the start of the string (i.e. anything). The pattern I have used matches any string with an M at the start.

match leading dots in bash if using regex

Say I want to match the leading dot in a string ".a"
So I type
[[ ".a" =~ ^\. ]] && echo "ha"
ha
[[ "a" =~ ^\. ]] && echo "ha"
ha
Why am I getting the same result here?
You need to escape the dot it has meaning beyond just a period - it is a metacharacter in regex.
[[ "a" =~ ^\. ]] && echo "ha"
Make the change in the other example as well.
Check your bash version - you need 4.0 or higher I believe.
There's some compatibility issues with =~ between Bash versions after 3.0. The safest way to use =~ in Bash is to put the RE pattern in a var:
$ pat='^\.foo'
$ [[ .foo =~ $pat ]] && echo yes || echo no
yes
$ [[ foo =~ $pat ]] && echo yes || echo no
no
$
For more details, see E14 on the Bash FAQ page.
Probably it's because bash tries to treat "." as a \ character, like \n \r etc.
In order to tell \ & . as 2 separate characters, try
[[ "a" =~ ^\\. ]] && echo ha