web-dev-qa-db-ja.com

bashの複数のオプションの比較(文字列)

readコマンドを使用するときに特定のオプションのみを有効にし、間違った可能性が入力された場合はスクリプトを終了しようとしています。

多くの可能性(配列、変数、構文の変更)を試しましたが、それでも最初の問題が解決しません。

ユーザーの入力をテストして、残りのスクリプトの実行を\禁止する方法を教えてください。

#!/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
4
Busted

ケースを使用しないのはなぜですか?

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 

地域の名前を入力する必要がないようにして、ユーザーの生活を少し楽にしてみませんか?

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

ユーザーがリストから有効な数値オプション以外を入力すると、$regionの値は空の文字列になり、エラーメッセージが表示されます。選択が有効な場合、ループは終了します。

それを実行する:

$ 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
5
Kusalananda

問題はこれにあります:

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

-oorを意味し、完全な条件が必要なので、

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

毎回$textをテストする方法をご覧ください。

あなたのlogicも間違っています。 -aおよび); 「us-east-1」でない場合and「us-west-2」でない場合andない...

そう

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

この種のテストを行う方法は他にもあります。一部は単に「個人的な好み」です。ただし、この構文を使用すると、元の形式と構造に従うことができます。

4
Stephen Harris

コマンドラインオプションを使用できるようにする(以前のコマンドラインを編集して再利用する方が簡単で、スクリプトで使いやすい)のではなく、質問をするスクリプトには本当に耐えられないので、次のようにgetoptsを使用します。

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

いくつかの例を実行します:

_$ ./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
_
2
cas

あなたはこのようなことをすることができます:

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

有効な値はbash配列に保存されます。これは、表示と入力文字列のテストの両方に使用できます。

-o in testには完全な条件が必要です。使用してはいけない引数もあります

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

代わりに

[ "$x" != "foo" ] && [ "$x" != "bar" ] 
1
ilkkachu