Comparing multiple options in a bash (string)
Solution 1
Why don't you use case?
case $text in
us-east-1|us-west-2|us-west-1|eu-central-1|ap-southeast-1|etc)
echo "Working"
;;
*)
echo "Invalid option: $text"
;;
esac
Solution 2
Why not make the life of the user a bit easier by not requiring them to type the name of the region at all?
#!/bin/bash
echo "Select region"
PS3="region (1-10): "
select region in "us-east-1" "us-west-2" "us-west-1" "eu-central-1" \
"ap-southeast-1" "ap-northeast-1" "ap-southeast-2" \
"ap-northeast-2" "ap-south-1" "sa-east-1"
do
if [[ -z $region ]]; then
echo "Invalid choice: '$REPLY'" >&2
else
break
fi
done
echo "You have chosen the '$region' region"
If the user types in anything other than a valid numerical option from the list, the value in $region
will be an empty string and we display an error message. If the choice is valid, the loop exits.
Running it:
$ bash script.sh
Select region
1) us-east-1 4) eu-central-1 7) ap-southeast-2 10) sa-east-1
2) us-west-2 5) ap-southeast-1 8) ap-northeast-2
3) us-west-1 6) ap-northeast-1 9) ap-south-1
region (1-10): aoeu
Invalid choice: 'aoeu'
region (1-10): .
Invalid choice: '.'
region (1-10): -1
Invalid choice: '-1'
region (1-10): 0
Invalid choice: '0'
region (1-10): '
Invalid choice: '''
region (1-10): 5
You have chosen the 'ap-southeast-1' region
Solution 3
The problem is with this:
[ "$text" != 'us-east-1' -o us-west-2 -o ... ]
The -o
means or and you need a full condition, so it would be
[ "$text" != 'us-east-1' -o "$text" != 'us-west-2' -o ... ]
See how we're having to test $text
each time?
Your logic is also wrong; you want -a
(and); if it's not "us-east-1" and it's not "us-west-2" and it's not...
So
[ "$text" != 'us-east-1' -a "$text" != 'us-west-2' -a ... ]
There are other ways of doing this sort of test; some of which are merely "personal preference". However this syntax should get you going and follows the form and structure of your original.
Solution 4
I really can't stand scripts that ask me questions rather than allow me to use command line options (easier to edit and re-use previous command lines, easier to use in a script), so I'd use getopts
like this:
#!/bin/bash
regions=(us-east-1 us-west-2 us-west-1 eu-central-1 ap-southeast-1
ap-northeast-1 ap-southeast-2 ap-northeast-2 ap-south-1
sa-east-1)
region=0 # default to region 0, us-east-1
usage() {
[ -n "$1" ] && printf '%s\n\n' "$@"
echo "Usage: $0 [ -r region-number|\"list\"] ..."
# print more help here
exit 1
}
list_regions() {
[ -n "$1" ] && printf '%s\n\n' "$@"
printf '%s\n' "${regions[@]}" | cat -n
exit 1
}
check_region() {
[ "$region" == "list" ] && list_regions
[[ ! "$region" =~ ^[0-9]+$ ]] && usage "Region code must be numeric"
region=$((region - 1)) # bash arrays are zero-based
[ -z "${regions[$region]}" ] || \
[ "$region" -lt 0 ] && list_regions "Unknown region code"
}
while getopts 'r:h' opt ; do
case "$opt" in
r) region="$OPTARG" ; check_region ;;
h) usage ;;
*) usage ;;
esac
done
shift $(($OPTIND - 1))
# do whatever with "$region" and/or "${regions[$region]}"
echo region="${regions[$region]}"
Some example runs:
$ ./busted.sh
region=us-east-1
$ ./busted.sh -r
./busted.sh: option requires an argument -- r
Usage: ./busted.sh [-r region-number|"list"] ...
$ ./busted.sh -r list
1 us-east-1
2 us-west-2
3 us-west-1
4 eu-central-1
5 ap-southeast-1
6 ap-northeast-1
7 ap-southeast-2
8 ap-northeast-2
9 ap-south-1
10 sa-east-1
$ ./busted.sh -r 99
Unknown region code
1 us-east-1
2 us-west-2
3 us-west-1
4 eu-central-1
5 ap-southeast-1
6 ap-northeast-1
7 ap-southeast-2
8 ap-northeast-2
9 ap-south-1
10 sa-east-1
$ ./busted.sh -r 7
region=ap-southeast-2
Solution 5
You could do something like this:
valid=(foo bar doo)
echo enter something, valid values: "${valid[@]}"
read text
ok=0
for x in "${valid[@]}" ; do
if [ "$text" = "$x" ] ; then ok=1 ; fi ;
done
echo is it ok: $ok
The valid values are saved in a bash array, which can be used both for display and to test the input string.
Apart from the fact that -o
in test
need a full condition, there are also arguments that one shouldn't use
[ "$x" != "foo" -a "$x" != "bar" ]
but instead
[ "$x" != "foo" ] && [ "$x" != "bar" ]
Related videos on Youtube
Busted
Updated on September 18, 2022Comments
-
Busted over 1 year
I'm trying to enable only certain options when using the
read
command, and to exit the script if a wrong possibility was entered.Tried many possibilities (array, variables, syntax change), but I'm still stuck with my initial problem.
How do I test the input of the user and allow \ disallow to run the rest of the script?
#!/bin/bash red=$(tput setaf 1) textreset=$(tput sgr0) echo -n 'Please enter requested region > ' echo 'us-east-1, us-west-2, us-west-1, eu-central-1, ap-southeast-1, ap-northeast-1, ap-southeast-2, ap-northeast-2, ap-south-1, sa-east-1' read text if [ -n $text ] && [ "$text" != 'us-east-1' -o us-west-2 -o us-west-1 -o eu-central-1 -o ap-southeast-1 -o ap-northeast-1 -o ap-southeast-2 -o ap-northeast-2 -o ap-south-1 -o sa-east-1 ] ; then echo 'Please enter the region name in its correct form, as describe above' else echo "you have chosen ${red} $text ${textreset} region." AWS_REGION=$text echo $AWS_REGION fi
-
Stéphane Chazelas almost 8 years
-
-
Busted almost 8 yearsAwesome answer ! I'll be sure to check this out. In my case , since it is a part of a bigger script with many implication- (money for starters), I don't want to hear later on- oopsy.. did I set up the whole environment in another region? - didn't mean too..
-
Stéphane Chazelas almost 8 yearsA simpler way to check for a valid entry is to check
$region
against the empty string. See also$PS3
to change the prompt. Better to issue the error on stderr. -
Kusalananda almost 8 years@StéphaneChazelas Much appreciated! Will edit.
-
Kusalananda almost 8 years@StéphaneChazelas Sorry to ask a question here, but do you have any clues as to why the
PS3
prompt is actually displayed on stderr? -
Stéphane Chazelas almost 8 years@Kusalananda, same for the choice or for bash's prompt or
read -p
. It's not standard output of your script, not something that you would pipe to something else. It's only for user interaction. If you redirect the script's output, you'll still want to see those prompts. -
Busted almost 8 yearsGreat answer! simple and easy, I've even added an error message in case anyone just press 'enter' (which display $text as an empty field- so although it is the correct behavior, it seems like an error)(stackoverflow.com/questions/17575392/…)
-
Busted almost 8 yearsThank you for explaining it, It seems I did messed up the logic- oddly enough I did try it like you said, I guess I was too tired..
-
Luciano Andress Martini almost 8 yearsYou can add this clause "") echo "Please enter some data" ;;. Note that it needs to come first than *) clause.
-
Luciano Andress Martini almost 8 yearsHellow friend, very nice script! +1
-
Alessio almost 8 yearsthanks. on looking at this again, it's a little too verbose for my liking so I'd probably make the "Unknown region code" error message just say
use '-r list' for a list
rather than printing the entire list. and usecolumn
or something in thelist_regions
function so that the list didn't take up so many output lines.