Case 問い合わせ AND 演算子

Case 問い合わせ AND 演算子

次のコードがあります。

read -p "Enter a word: " word

case $word in
  [aeiou]* | [AEIOU]*)
          echo "The word begins with a vowel." ;;
  [0-9]*)
          echo "The word begins with a digit." ;;
  *[0-9])
          echo "The word ends with a digit." ;;
  [aeiou]* && [AEIOU]* && *[0-9])
          echo "The word begins with vowel and ends with a digit." ;;
   ????)
          echo "You entered a four letter word." ;;
   *)
          echo "I don't know what you've entered," ;;
esac

私がこれを実行したとき:

Enter a word: apple123
case2.sh: line 10: syntax error near unexpected token `&&'
case2.sh: line 10: `  [aeiou]* && [AEIOU]* && *[0-9])'

Case 文は AND 演算子をサポートしていないようで、上記の Case 文では && 演算子は論理的に正しくないと思います。

if elseを使用して、入力がコレクションと数字で始まるかどうかを確認できます。しかし、ケースにAND演算子などの組み込み関数があるかどうか疑問に思います。

答え1

あなたは正しいです。標準定義caseパターンにはAND演算子は使用できません。 「小文字の集まりで始まり、大文字の集まりで始まります」と言うと、何も一致しないことも正しいです。また、パターンと説明が数値テストの開始/終了を逆にすることに注意してください。[0-9]*単語に一致するパターンを使用してください。スタート数字ではありません終わり数字で。

1つのアプローチは、テストを同じパターンにグループ化することです。最も厳しいパターンから始まります。

case $word in
  ([AaEeIiOoUu]??[0-9]) echo it is four characters long and begins with a vowel and ends with a digit;;
  ([AaEeIiOoUu]*[0-9])  echo it is not four characters long begins with a vowel and ends with a digit;;
# ...
esac

別の(長時間!)アプローチは、caseステートメントをネストして、毎回適切な応答を構築することです。コレクションから始めますか?はいまたはいいえ?さて、数字で終わります、はい、またはいいえ?これはすぐに扱いにくく、メンテナンスが面倒になる可能性があります。

別のアプローチは、「否定的な」フィードバックを提供したい場合は、一連のcase文を使用して適用可能な文の文字列(または配列)を構築することです(「単語true;*いいえコレクションから始めます」など)。

result=""
case $word in
  [AaEeIiOoUu]*)
          result="The word begins with a vowel." ;;
esac

case $word in
  [0-9]*)
          result="${result} The word begins with a digit." ;;
esac

case $word in
  *[0-9])
          result="${result} The word ends with a digit." ;;
esac

case $word in
   ????)
          result="${result} You entered four characters." ;;
esac

printf '%s\n' "$result"

いくつかの例:

$ ./go.sh
Enter a word: aieee
The word begins with a vowel.
$ ./go.sh
Enter a word: jeff42
 The word ends with a digit.
$ ./go.sh
Enter a word: aiee
The word begins with a vowel. You entered four characters.
$ ./go.sh
Enter a word: 9arm
 The word begins with a digit. You entered four characters.
$ ./go.sh
Enter a word: arm9
The word begins with a vowel. The word ends with a digit. You entered four characters.

または、casebash は文の構文を拡張します。次にパターンを終了すると、複数のパターンを選択できます;;&

shopt -s nocasematch
case $word in
  [aeiou]*)
          echo "The word begins with a vowel." ;;&
  [0-9]*)
          echo "The word begins with a digit." ;;&
  *[0-9])
          echo "The word ends with a digit." ;;&
   ????)
          echo "You entered four characters." ;;
esac

*この方法でパターンをナビゲートすると、何でも一致するため、包括的なパターンを削除しました。 Bashには上記で設定したシェルオプションもあります。nocasematchこれにより大文字と小文字を区別せずにパターンを一致させることができます。これは重複を減らすのに役立ちます。| [AEIOU]*パターンの一部を削除しました。

いくつかの例:

$ ./go.sh
Enter a word: aieee
The word begins with a vowel.
$ ./go.sh
Enter a word: jeff42
The word ends with a digit.
$ ./go.sh
Enter a word: aiee
The word begins with a vowel.
You entered four characters.
$ ./go.sh
Enter a word: 9arm
The word begins with a digit.
You entered four characters.
$ ./go.sh
Enter a word: arm9
The word begins with a vowel.
The word ends with a digit.
You entered four characters.

答え2

完全性のためにOR演算子caseはあります|が、AND演算子はありませんが、拡張glob演算子(ksh、zsh、bash)でシェルを使用する場合は、次のことができます。模様通事論:

  • ksh93オペレーター@(x&y&z):

      case $string in
        ( @({12}(?)&~(i:[aeiou]*)&*[0123456789]) )
          echo is 12 characters long AND starts with a vowel AND ends in a decimal
      esac
    
  • zsh~((NOT)と組み合わせて(AND-NOT)を使用してください^。)x~^y~^z

      set -o extendedglob
      case $string in
        ( ?(#c12)~^(#i)[aeiou]*~^*[0-9] )
          echo is 12 characters long AND starts with a vowel AND ends in a decimal
      esac
    
  • ksh88, , bashOR( ) を使用した!(!(x)|!(y)|!(z))二重否定

      shopt -s extglob # bash only
      case $string in
        ( !(!(????????????)|!([aAeEıiIİoOuU]*)|!(*[0123456789])) )
          echo is 12 characters long AND starts with a vowel AND ends in a decimal
      esac
    

いずれにせよ、zshの範囲は常にコードポイント値に基づいていることを除いて、同様の範囲は[0-9]POSIX / Cロケールの外では安定して使用できません(したがって[0123456789]上記の代替)。

ksh93とzshの大文字と小文字を区別しない一致演算子(~(i)および(#i))は、大文字と小文字の区別を比較するためにロケールに従います。たとえば、GNUシステムのトルコ語ロケールには(#i)[aeiou]一致がありますが、大文字があるため一致İしません。 (ロケールに関係なく)一貫した結果を得るには、ksh88 / bashアプローチではなく可能なすべての値をハードコーディングすることをお勧めします。Iiİ

答え3

通常持ち運べるCase ステートメントで AND を実装するソリューションは、ブール値を連結することです。

case $A$B in
    11) echo "Both conditions are true";;
    1*) echo "Condition A is true";;
    *1) echo "Condition B is true";;
    00) echo "Both conditions are false";;
     *) echo "There is an unexpected error";;
esac

あなたのユースケースについて:

printf "Enter a word: "; read word

A=0 B=0 C=0

case $word in    ( [aeiouAEIOU]* ) A=1;; esac
case $word in    ( *[0-9]        ) B=1;; esac
case $word in    ( ????          ) C=1;; esac

case $A$B$C in
  111)     echo "Four letters that start with a vowel and end with a digit" ;;
  11*)     echo "The word begins with a vowel AND ends with a digit."       ;;
  1* )     echo "The word begins with a vowel."                             ;;
  *1?)     echo "The word ends with a digit."                               ;;
   *1)     echo "The word is four letters long"                             ;;
    *)     echo "I don't understand what you've entered,"                   ;;
esac

各ブールオプションはポータブルシェルを使用します。;;&bashまたはzshで使用できます;|。残念ながら、kshにはそのようなオプションはありません。

ブール値を設定する別の方法(少なくともいくつかのシェル:ksh、bash、zsh)は次のとおりです。

[[ $word ==   [aeiouAEIOU]* ]] && A=1 || A=0
[[ $word ==   *[0-9]        ]] && B=1 || B=0
[[ $word ==   ????          ]] && C=1 || c=0

関連情報