web-dev-qa-db-ja.com

ケース+ケース構文で等しいかそれ以下またはそれ以上を実装する方法

私の目標は、(case + esacでのみ)で番号の範囲を確認し、その範囲を出力することです。だから例えば:

  • 数値が0〜80の場合は、>=0<=80を出力します
  • 数値が81から100の間の場合は、>=81<=100を出力します
  • 等.

以下の私のスクリプトの問題は、0〜9の数値の場合にのみ>=0<=90のみを印刷します。スクリプトを修正して、数値の範囲に従って正しい出力を印刷する方法を教えてください。

#!/bin/ksh
read number 
case $number in 
 [0-80])  echo ">=0<=80";; 
 [81-100]) echo ">=81<=100";; 
 [101-120]) echo ">=101<=120";;
 [121-300]) echo ">=121<=300";;
esac
9
yael

caseはパターンマッチング専用であり、算術評価を行いません(zsh<x-y>拡張パターンマッチング演算子を検討する場合を除いて)。 [...]は、指定されたセットに基づいてone文字(または一部の実装では照合要素)に一致するだけです。したがって、たとえば、[0-80]は、0から8または0(つまり、0、1、2、3、4、5、6、7、8のいずれか)であれば、-one文字に一致します。

次のようなパターンで数字を照合できます。

case $(($number)) in
  ([0-9]|[1-7][0-9]|80) echo ">=0<=80";;
  (8[1-9]|9[0-9]|100) echo ">=81<=100";;
  ... and so on
esac

しかし、それが適切なツールではないことが簡単にわかります。

[...]は、one文字を指定された文字のリストと照合します。したがって、[121-300]は、1、2、1〜3、0または0の任意の文字と照合されます。したがって、 [0-3]または[0123]

使用する:

if [ "$number" -ge 0 ] && [ "$number" -le 80 ]; then
  echo ">=0<=80"
Elif [ "$number" -ge 81 ] &&  [ "$number" -le 100 ]; then
  echo ">=81<=100"
Elif ... and so on
  ...
fi

caseを使用する別の方法は次のようになります。

case $((
  (number >= 0 && number <= 80)   * 1 +
  (number > 80 && number <= 100)  * 2 +
  (number > 100 && number <= 120) * 3 +
  (number > 120 && number <= 300) * 4)) in
  (1) echo ">=0<=80";;
  (2) echo ">=81<=100";;
  (3) echo ">=101<=120";;
  (4) echo ">=121<=300";;
  (0) echo "None of the above";;
esac

または、三項演算子(x ? y : z)を使用します。

case $((
  number >= 0 && number <= 80   ? 1 :
  number > 80 && number <= 100  ? 2 :
  number > 100 && number <= 120 ? 3 :
  number > 120 && number <= 300 ? 4 : 0)) in...

または、@ mikeservのように、ボックスの外側で考えます caseロジックを逆にして、1をこれらの算術比較の値と照合します

6

実際、これはとても簡単です。 caseについての重要な点は、パターンとの最初の一致を見つけるために必要なだけ拡張されることです。それは仕様の振る舞いです。そして、あなたはそれを既知の文字列で設定し、パターンの展開を評価することができます。

case  1:${number:--} in
(1:*[!0-9]*|1:0*[89]*)
  ! echo NAN
;;
($((number<81))*)
    echo "$number >=0<=80"
;;
($((number<101))*)
    echo "$number >=81<=100"
;;
($((number<121))*)
    echo "$number >=101<=120"
;;
($((number<301))*)
    echo "$number >=121<=300"
;;
esac

caseは、パターンの先頭の1を見つけるために必要以上にこれらのパターンを展開することはありません。これは、ユーザー入力を操作する場合に特に重要です。これは、実際にそれを入れている同じcaseステートメントで算術展開コンテキストに入れようとする前に、$numberの内容を安全に検証できることを意味します数学の拡張。

4
mikeserv

これはあまりいい方法ではありませんが、これを使用できます。

 #!/bin/ksh

read number  

case $number in
[0-9]|[1-7][0-9]|80) echo  echo ">=0<=80";;
8[1-9]|9[0-9]|100) echo ">=81<=100";;
10[1-9]|11[0-9]|120) echo ">=101<=120";;
12[1-9]|130) echo ">=121<=300";;
esac
1
Poulpatine