Regex star produces no match - regex

If memory serves I used to be able to do this
$ [[ abc123 =~ ([0-9]*) ]]
$ echo ${BASH_REMATCH[1]}
as you can see its giving no output with the star * character. Now it only works if I use the plus + character.
$ [[ abc123 =~ ([0-9]+) ]]
$ echo ${BASH_REMATCH[1]}
123
edit see more strangeness. It will match the start of the string, but not the end of the string.
$ [[ 123abc =~ ([0-9]*) ]]
$ echo ${BASH_REMATCH[1]}
123

Your regex returns the first match that it finds, that is position 0, before the "a", there it matches the empty string.
* as quantifier is difficult, because if that is the whole expression, it is able to match the empty string, and therefor it will match on each position where is no digit to match.
So in the string "abc123" it matches 4 times!
a b c 123
^ ^ ^ ^..
the first 3 times it is happy to match the empty string and on the fourth position it matches the series of digits.

Related

how to write conditions in regex

Trying regex for following strings
JIRAID-12314 >> should match
JIRAID-21312 test >> should match
JIRAID-12312-test >> should not match
if [[ $MESSAGE =~ ^$JIRAID-[0-9]{4,6}[\s\w]* ]];
then
echo "string matched
exit 0
How can I stop matching 3rd string?
You may use this regex in bash:
re='^JIRAID-[0-9]{4,6}( [[:alnum:]]+)?$'
RegEx Details:
^: Start
JIRAID-: Match JIRAID- text
[0-9]{4,6}: Match 4 to 6 digits
( [[:alnum:]]+)?: Optional group to match a space followed by 1+ alpha numeric characters
$: End
RegEx Demo
Code Demo
Code:
re='^JIRAID-[0-9]{4,6}( [[:alnum:]]+)?$'
for s in 'JIRAID-12314' 'JIRAID-21312 test' 'JIRAID-12312-test'; do
[[ $s =~ $re ]] && echo "$s matched" || echo "$s didn't match"
done

Regex match validation for less than n or n times

Suppose I have regex as below : [a-z]{1,28}
This will match the below string as per two matches given below:
abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz
Match 1
Full match 0-28 abcdefghijklmnopqrstuvwxyzab
Match 2
Full match 28-52 cdefghijklmnopqrstuvwxyz
I want to match only 28 or less than 28 characters on that.That means if my string is greater than 28 character,my validation should fail.
Please advise on the above.The problem I am facing is in when I am defining this validation xsd pattern(xs:pattern value="[a-z]{1,28}")
Thanks in advance
Use word boundaries \b to denote the needed sequence:
echo "abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz" | egrep '\b[a-z]{1,28}\b'
# won't find the matches
echo "abcdefghijklmnopqrstuvwxyzab abc" | egrep -o '\b[a-z]{1,28}\b'
Outputs:
abcdefghijklmnopqrstuvwxyzab
abc
match with beginning/end of string.
str="abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyz"
# Your solution.
if [[ $str =~ [a-z]{1,28} ]]; then
echo "First match"
fi
# Solution `matching complete line
if [[ $str =~ ^[a-z]{1,28}$ ]]; then
echo "Second match"
fi

regex issue Bash

I'm studying bash programming , in particular the regex and I found this code:
numpat='^[+-]([0-9]+)$'
strpat='^([a-z]*)\1$'
read stringa
if [[ $stringa =~ $numpat ]]
then
echo "numero"
echo numero > output
exit ${BASH_REMATCH[1]}
elif [[ $stringa =~ $strpat ]]
then
echo "echo"
echo echo > output
exit 11
fi
and I don't understand what means \1 in this line:
strpat='^([a-z]*)\1$'
\1 is a backreference. It matches whatever was matched by the first capture group ([a-z]*).
So the pattern ^([a-z]*)\1$ matches a string that built from a substring that's repeated twice, such as foofoo. The capture group matches the first foo, and the backreference matches the second foo. But if the string is foobar, the backreference never matches anything, because it can't find another repetition of any of the initial strings.
You can allow any number of repetitions by using the + quantifier after \1. This matches it one or more times.
DEMO
On cygwin, which uses newlib, \1 matches only 1.
if [[ a1 =~ $strpat ]]; then echo YES; fi # YES

Bash regex: replace string with any number of characters

I'm trying to remove colouring codes from a string; e.g. from: \033[36;1mDISK\033[0m to: DISK
my regex looks like this: \033.*?m so match '\033' followed by any number of chars, terminated by 'm'
when I search for the pattern, it finds a match; [[ "$var" =~ $regex ]] evaluates to true
however when I try to replace matches, nothing happens and the same string is returned.
Here's my complete script:
regex="\033.*?m"
var="\033[36;1mDISK\033[0m"
if [[ "$var" =~ $regex ]]
then
echo "matches"
echo ${var//$regex}
else
echo "doesn't match!"
fi
The problem appears to be with the match any number of any character part of the regex. I can successfully replace DISK but if I change that to D.*K or D.*?K it fails.
Note in all above cases the pattern claims to match the string but fails when replacing. Not too sure where to go with this now, any help appreciated.
Thanks
The following should do it:
$ var="\033[36;1mDISK\033[0m"
$ newvar=$(printf ${var} | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g")
$ echo ${newvar}
returns:
DISK
Now verify!
$ echo $var | od
0000000 030134 031463 031533 035466 066461 044504 045523 030134
0000020 031463 030133 005155
0000026
$ echo $newvar | od
0000000 044504 045523 000012
0000005
To use the parameter expansion substitution operator, you need to use an extended glob.
shopt -s extglob
newvar=${var//\\033\[*([0-9;])m}
To break it down:
\\033\[ - match the encoded escape character and [.
*([0-9;]) - match zero or more digits or semicolons. You could use +([0-9;]) to (more correctly?) match one or more digits or semicolons
m - the trailing m.

What does this match : bash regex

if [[ "$len" -lt "$MINLEN" && "$line" =~ \[*\.\] ]]
This is from Advanced bash scripting guide "Example 10-1. Inserting a blank line between paragraphs in a text file"
As I understand this matches "any string or a dot character". Right ?
It matches zero or more open bracket characters (\[*), followed by a period and a close square bracket (\.\]). Note that it only requires that a match exist somewhere in "$line", not that the whole string match. Here's a demo:
$ showmatch() { [[ "$1" =~ \[*\.\] ]] && echo "matched: '${BASH_REMATCH[0]}'" || echo "no match"; }
$ showmatch "abc[.]def"
matched: '[.]'
$ showmatch "abc.]def"
matched: '.]'
$ showmatch "abc[[[[[[[.]def"
matched: '[[[[[[[.]'
$ showmatch "abc[[[[[[[xyz.]def"
matched: '.]'
$ showmatch "abc[[[[[[[.xyz]def"
no match
...and I'm pretty sure that's not what it's supposed to be doing in that example script.
It means any string ended with dot inside bracers, for example: [.]
[abc.]
Update: +1 to Gordon Davisson, who has summed it up pretty well... so I've redacted my original post
In brief: You can test the result of a bash regex match like this:
[[ "[*.]" =~ \[*\.\] ]] ; echo ${BASH_REMATCH[0]}