次のコードがあります。
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.
または、case
bash は文の構文を拡張します。次にパターンを終了すると、複数のパターンを選択できます;;&
。
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
, ,bash
OR( ) を使用した!(!(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アプローチではなく可能なすべての値をハードコーディングすることをお勧めします。I
i
İ
答え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