Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

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
share|improve this question
up vote 6 down vote accepted

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 
share|improve this answer
    
Great 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 16 hours ago
    
You can add this clause "") echo "Please enter some data" ;;. Note that it needs to come first than *) clause. – Luciano Andress Martini 12 hours ago

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
share|improve this answer
    
Awesome 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.. – Busted yesterday
1  
A 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. – Stéphane Chazelas yesterday
    
@StéphaneChazelas Much appreciated! Will edit. – Kusalananda yesterday
    
@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? – Kusalananda yesterday
2  
@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. – Stéphane Chazelas yesterday

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.

share|improve this answer
    
Thank 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.. – Busted 15 hours ago

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" ] 
share|improve this answer

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
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.