Reputation: 313
I want a variable whose value should be in already defined range.
for e.g.
variable DAY=$1
should only get values Mon,Tue,Wed,Thus,Fri,Sat,Sun.
if user enter something else, it will not accept it.
I know i can do this by defining array or normally a variable storing all the days and then check variable DAY in a "for or while" loop.
But i want the simplest way without loop.
Thanks in advance.
Upvotes: 1
Views: 95
Reputation: 95307
To expand slightly on anubhava's answer:
arr=(Mon Tue Wed Thus Fri Sat Sun)
read -p 'Enter day value: ' day
case "${arr[@]}" in *"$day"*) echo "in range";; esac
Basically, this is building an array, turning it into a string, and doing a pattern match on it.
In the context of a case
expression, there's no difference between "${arr[@]}"
and "${arr[*]}"
; I personally would stick with *
, which makes it clearer that you're building one big string instead of a list of separate ones.
With this specific set of values, you don't have to worry about substring overlap, but the above check is still overly forgiving. For instance, if you enter u
, it will be considered "in range". That may not be what you want.
A more exact test would be something like this:
case "${arr[*]}" in
"$day "*|*" $day "*|*" $day") echo "in range";;
*) echo "not in range";;
esac
This still permits the user to enter multiple days as "Mon Tue" or similar; an easy way to fix that in this particular case is to change the read
line from read day
to read day _
.
The "$day "*
pattern will match at the beginning of the array (so if they enter Mon
in this case). The *" $day"
pattern will match at the end of the array (Fri
), and the *" $day "*
pattern will match the rest. Nothing else but an exact day string will match.
Also, here you can see how to handle the else
case - a pattern of *
matches anything that hasn't already matched something else, so that's the equivalent of else
in a case
.
Upvotes: 0
Reputation: 531605
Use the extended glob support to match exactly one of a list of choices.
range="Mon|Tue|Wed|Thu|Fri"
read day
if [[ $day = @($range) ]]; then
echo "$day is valid"
else
echo "$day is not valid"
fi
Upvotes: 2
Reputation: 785376
Without using a loop you can do something like this:
EOL=$'\n'
arr=(Mon Tue Wed Thus Fri Sat Sun)
read -p 'Enter day value: ' day
Tue
[[ $(printf "$EOL%s$EOL" "${arr[@]}") == *"$EOL$day$EOL"* ]] &&
echo "in range" || echo "not in range"
in range
read -p 'Enter day value: ' day
ue We
[[ $(printf "$EOL%s$EOL" "${arr[@]}") == *"$EOL$day$EOL"* ]] &&
echo "in range" || echo "not in range"
not in range
Upvotes: 1
Reputation: 189577
There's really no need for an array.
read -r day
case ' Mon Tue Wed Thu Fri Sat Sun ' in
*" $day "*)
echo "in range";;
*) echo "not in range";;
esac
Notice the spaces around the string expressions.
If you need to be strict, you should reject "Tue Wed" which this doesn't do. It would require a second case
wrapper, which is clunky but not completely unwieldy.
Upvotes: 0