Comparando várias opções em um bash (string)

4

Estou tentando ativar apenas algumas opções ao usar o comando read e sair do script se uma possibilidade errada foi inserida.

Tentei muitas possibilidades (matriz, variáveis, alteração de sintaxe), mas ainda estou preso ao meu problema inicial.

Como faço para testar a entrada do usuário e permitir \ não permitir que o restante do script seja executado?

#!/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
    
por Busted 25.07.2016 / 16:05

5 respostas

6

Por que você não usa o caso?

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 
    
por 25.07.2016 / 16:26
5

Por que não facilitar um pouco a vida do usuário ao não exigir que eles digam o nome da região?

#!/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"

Se o usuário digitar algo diferente de uma opção numérica válida da lista, o valor em $region será uma string vazia e exibiremos uma mensagem de erro. Se a escolha for válida, o loop sai.

Executando:

$ 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
    
por 25.07.2016 / 17:08
4

O problema é com isto:

[ "$text" != 'us-east-1' -o us-west-2 -o ... ]

O -o significa ou e você precisa de uma condição completa, por isso seria

[ "$text" != 'us-east-1' -o "$text" != 'us-west-2' -o ... ]

Veja como estamos tendo que testar $text a cada vez?

Sua lógica também está errada; você quer -a ( e ); se não for "us-east-1" e não é "us-west-2" e não é ...

Então

[ "$text" != 'us-east-1' -a "$text" != 'us-west-2' -a ... ]

Existem outras maneiras de fazer esse tipo de teste; alguns dos quais são meramente "preferência pessoal". No entanto, esta sintaxe deve levá-lo e segue a forma e estrutura do seu original.

    
por 25.07.2016 / 16:15
2

Eu realmente não suporto scripts que me façam perguntas em vez de permitir que eu use opções de linha de comando (mais fácil de editar e reutilizar linhas de comando anteriores, mais fácil de usar em um script), então usaria getopts assim:

#!/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]}"

Alguns exemplos são executados:

$ ./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
    
por 26.07.2016 / 03:09
1

Você poderia fazer algo assim:

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

Os valores válidos são salvos em uma matriz bash, que pode ser usada para exibição e para testar a string de entrada.

Além do fato de que -o in test precisa de uma condição completa, há também argumentos que não se deve usar

[ "$x" != "foo" -a "$x" != "bar" ] 

mas em vez disso

[ "$x" != "foo" ] && [ "$x" != "bar" ] 
    
por 25.07.2016 / 16:19