I have tried creating a regex validation for Bash and have been doing this. It's working only for the first digit, the second one no. Can you help me out here?
while [[ $usrInput =~ [^[1-9]|[0-2]{1}$] ]]
do
echo "This is not a valid option. Please type an integer between 1 and 12"
read usrInput
done
You can't nest ranges. You want something like
while ! [[ $usrInput =~ ^[0-9]|11|12$ ]]; do
although in general it would be simpler to compare a digit string numerically:
min=1
max=12
until [[ $usrInput =~ ^[0-9]+$ ]] &&
(( usrInput >= min && usrInput <= max )); do
I believe you (or bash) are not grouping the expressions correctly. Either way, this'll work:
while read usrInput
do
if [[ "$usrInput" =~ ^([1-9]|1[0-2])$ ]]
then
break
else
echo "Number not between 1 and 12"
fi
done
Related
I have some test brackets in a script, which works well for me, but I suspect there's an easier way to do this. For the expression below is there a way to do this with a single regex rather than using two separate checks?
Basically if the second number is 1 I want to match 0-9 for the third number, but if the second number is 2, I only want to match 0 or 1. I have a feeling there's a more simple way to accomplish this than using two separate comparisons and was just curious if someone knew a better way.
#! /bin/sh
[[ "${Var}" =~ 1.1.[0-9].* ]] || [[ "${Var}" =~ 1.2.[0-1].* ]] && echo true || echo false
Thanks to sln, the final result is.
=~ 7.(1.(10|[0-9])|2.[0-1])-.*
The shell-agnostic (posixly portable) way to do this is
case $var in
(1.1.[0-9].*|1.2.[01].*) echo true;;
(*) echo false;;
esac
Note how easily this is extensible, in a readable way, to more patterns. You could also improve readability with
case $var in
(1.1.[0-9].*) echo true;;
(1.2.[01].*) echo true;;
(*) echo false;;
esac
Looking for a quick way in BASH to test whether my variable is single or multiline? I thought the following would work but it always comes back as no
input='foo
bar'
regex="\n" ; [[ $regex =~ "${input}" ]] && { echo 'yes' ; } || { echo 'no' ; }
You don't need regex as you can use glob pattern to check for this:
[[ $str == *$'\n'* ]] && echo "multiline" || echo "single line"
$str == *$'\n'* will return true if any newline is found in $str.
Change your regex like below,
$ regex="[\\r\\n]"
$ [[ "${input}" =~ $regex ]] && { echo 'yes' ; } || { echo 'no' ; }
yes
You do not need to use a regex. Just erase everything that is not a "new line", and count characters:
str=$'foo\nbar\nbaz'
Not calling any eternal program (pure bash):
b=${str//$'\n'}; echo $(( ${#str} - ${#b} ))
The number printed is the number of new lines.
An alternative solution is to cut the variable at the \n, and find if it got shorter:
b="${str%%$'\n'*}"; (( ${#b} < ${#str} )) && echo "Multiline"
Note that this will fail if the line end is \c (one CR, as in classic MAC).
I want to search within a string for a regex expression, I am doing this as follows:
Suppose target="string with 1234 in"
if [[ "$target" =~ "{4}\d" ]] then
val=...
fi
I want to capture the regex found i.e. I want val=1234. what's the best way to do this?
If you're only looking for the 4-digit number, you'd use /\b\d{4}\b/
If you're wanting to capture the val= part as well, simply prefix that, so you'd have /\bval=\d{4}\b/
And lastly, if you have a case where you don't know what the val of the val= part is, replace val with \w+, then you'd have /\b\w+=\d{4}\b/
Do you mean sth. like val = s/\D(\d\d\d\d)\D/$1/ , or val = /\d{4}/ ?
The matched parts are held in the .sh.match array in ksh:
if [[ $target == *{4}(\d)* ]]; then
val=${.sh.match[1]}
# do something with $val
fi
Demo:
$ target="string with 1234 in"
$ [[ $target == *{4}(\d)* ]] && echo "${.sh.match[1]}"
1234
Hi i am try to validate user inputs to be not empty and is a number or with decimal
re='^[0-9]+$'
while [ "$num" == "" ] && [[ "$num" ~= $re ]]
do
echo "Please enter the price : "
read num
done
I was able to run smooth with just the 1st condition. When i add 2nd condition my program couldn't run.
----EDIT----------
Ok i try changing and the program run. But when i enter a number it still prompting for input.
re='^[0-9]+$'
while [ "$num" == "" ] && [ "$num" != $re ]
do
echo "Please enter the price : "
read num
done
regualar expression can be used with the operator =~ not ~= like you used it.
An additional binary operator, =~, is available, with the same
prece dence as == and !=. When it is used, the string to the right of
the operator is considered an extended regular expression and matched
accordingly (as in regex(3)). The return value is 0 if the string
matches the pattern, and 1 otherwise. If the regular expression is
syntactically incorrect, the conditional expression's return value is
2. If the shell option nocasematch is enabled, the match is performed
without regard to the case of alphabetic characters. Any part of the
pattern may be quoted to force the quoted portion to be matched as a
string. Bracket expressions in regular expressions must be treated
carefully, since normal quoting characters lose their meanings between
brackets. If the pattern is stored in a shell variable, quoting the
variable expansion forces the entire pattern to be matched as a string.
Substrings matched by parenthesized subexpressions within the regular
expression are saved in the array variable BASH_REMATCH. The element
of BASH_REMATCH with index 0 is the portion of the string matching the
entire regular expression. The element of BASH_REMATCH with index n is
the portion of the string matching the nth parenthesized subexpression.
consider theese examples (0 true/match, 1 false/no match)
re=^[0-9]+; [[ "1" =~ ${re} ]]; echo $? # 0
re=^[0-9]+; [[ "a" =~ ${re} ]]; echo $? # 1
re=^[0-9]+; [[ "a1" =~ ${re} ]]; echo $? # 1
re=^[0-9]+; [[ "1a" =~ ${re} ]]; echo $? # 0 because it starts with a number
use this one to check for a number
re=^[0-9]+$; [[ "1a" =~ ${re} ]]; echo $? # 1 because checked up to the end
re=^[0-9]+$; [[ "11" =~ ${re} ]]; echo $? # 0 because all nums
UPDATE: If you just want to check if the user inputs a number combine the lesson learned above with your needs. i think your conditions do not fit. perhaps this snippet solves your issue completely.
#!/bin/bash
re=^[0-9]+$
while ! [[ "${num}" =~ ${re} ]]; do
echo "enter num:"
read num
done
This snippet just requests input if ${num} is NOT (!) a number. During the first run ${num} is not set so it will not fit at least one number, ${num} then evaluates to an empty string. Afterwards it just contains the input entered.
Your error is simple; the variable can't be both empty and a number at the same time. Maybe you mean || "or" instead of && "and".
You can do this with glob patterns as well.
while true; do
read -r -p "Enter a price: " num
case $num in
"" | *[!.0-9]* | *.*.*) echo invalid ;;
*) break;;
esac
First off, there is the classic logic trap demonstrated in the OP's question:
while [ "$num" == "" ] && [ "$num" != $re ]
The issue here is the && which pretty much means the moment the left expression is false, the entire expression is false. i.e. the moment somebody types a non empty response, it breaks the loop and the regular expression test is never used. To fix the logic problem, one should consider changing && to ||, i.e.
while [ "$num" == "" ] || [ "$num" != $re ]
The second issue, is we are testing for negative matches to regular expression, pattern. So, this is done in two parts, one we need to use [[ "$num" =~ $re ]] for regular expression testing. Then, we need to look for negative matches, i.e. append a ! which yields:
while [ "$num" == "" ] || ! [[ "$num" =~ $re ]
Having got this far, many people observed that there is actually no need to test for the empty string. That edge condition is already covered by the regular expression itself, so, we optimize out the redundant test. The answer now reduces to:
while ! [[ "$num" =~ $re ]
In addition to the above observation, here are my notes about regular expression ( some of the observation has been collated from other answers ):
regular expressions can be tested with the [[ "$str" =~ regex ]] syntax
regular expressions match with $? == 0 ( 0 == no error )
regular expressions do not match with $? == 1 ( 1 == error )
regular expressions do not seem to work when quoted. recommend using [0-9] not "[0-9]"
To implement a number validation, the following pattern seems to work:
str=""
while ! [[ "${str?}" =~ ^[0-9]+$ ]]
do
read -p "enter a number: " str
done
You can mix regular expression filters with regular arithmetic filters for some really nice validation results:
str=""
while ! [[ "${str?}" =~ ^[0-9]+$ ]] \
|| (( str < 1 || str > 15 ))
do
read -p "enter a number between 1 and 15: " str
done
N.B. I used the ${str?} syntax ( instead of $str ) for variable expansion as it demonstrates good practice for catching typos.
Trying to verify that a string has only lowercase, uppercase, or numbers in it.
if ! [[ "$TITLE" =~ ^[a-zA-Z0-9]+$ ]]; then echo "INVALID"; fi
Thoughts?
* UPDATE *
The variable TITLE currently only has upper case text so it should pass and nothing should be outputted. If however I add a special character to TITLE, the IF statement should catch it and echo INVALID. Currently it does not work. It always echos invalid. I think this is because my regex statement is wrong. I think the way I have it written, its looking for a title that has all three in it.
Bash 4.2.25
The idea is, the user should be able to add any title as long as it only contains uppercase, lowercase or numbers. All other characters should fail.
* UPDATE *
If TITLE = ThisIsAValidTitle it echos invalid.
If TITLE = ThisIs#######InvalidTitle it also echos invalid.
* SOLUTION *
Weird, well it started working when I simplified it down to this:
TEST="Valid0"
if ! [[ "$TEST" =~ [^a-zA-Z0-9] ]]; then
echo "VALID"
else
echo "INVALID"
fi
* REAL SOLUTION *
My variable had spaces in it... DUH
Sorry for the trouble guys...
* FINAL SOLUTION *
This accounts for spaces in titles
if ! [[ "$TITLE" =~ [^a-zA-Z0-9\ ] ]]; then
echo "VALID"
else
echo "INVALID"
fi
I'd invert the logic. Test for invalid characters and echo a warning if at least one is present:
if [[ "$TITLE" =~ [^a-zA-Z0-9] ]]; then
echo "INVALID"
fi
With that said, your original check worked for me, so you probably need to provide more context (i.e. a larger portion of your script).
why cant we use alnum
[[ 'mystring123' =~ [:alnum:] ]] && echo "ok" || echo "no"
the nominated answer is wrong. Because it doesn't check to the end of the string. also it's inverted. as the conditional says: "if the start of the string is valid characters then echo invalid"
[[ $TITLE =~ ^[a-zA-Z0-9_-]{3,20}$ ]] && ret="VALID" || ret="INVALID"
echo $ret