case +如何在大小写语法中实现等于或小于或等于


9

我的目标是使用(仅使用case+ esac)验证数字范围,然后打印该范围。因此,例如:

  • 如果数字介于0到80之间,请打印 >=0<=80
  • 如果数字介于81到100之间,则打印 >=81<=100
  • 等等

>=0<=90仅当数字介于0和9之间时,下面的脚本问题才会打印。如何修复脚本,以便根据数字范围打印正确的输出?

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

Answers:


6

case只进行模式匹配,也不会做算术评估(如果你考虑也许除外zsh<x-y>扩展模式匹配运算符)。的[...]是仅匹配一个(或字符排序元素基于内指定的集合在一些实施方式)。因此,例如,[0-80]如果一个字符是0to 80(即0、1、2、3、4、5、6、7、8中的一个),则将匹配一个字符。

您可以将数字与以下模式匹配:

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

但是您可以轻松地看到它不是正确的工具。

[...]匹配一个对指定的字符列表的字符,所以[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这些算术比较的值进行匹配


1
+1,考虑if [ n < 0 ] - elif [ n <= 80 ] - elif [ n <= 100 ] ... - else。更少的打字,更少的错误。
peterph

@peterph它也需要更长的时间才能运行。
肯·夏普

4

实际上,这确实很容易做到。关于的事情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。在使用用户输入时,这尤其重要,因为这意味着您可以$number在实际将其放入数学扩展的同一case语句中,将其放到算术扩展上下文中之前就可以安全地验证的内容。


👍我喜欢您在盒子外面/周围思考的方式。
斯特凡Chazelas

@StéphaneChazelas-我喜欢case。您可以使用$((数学来做一些很酷的事情))case尤其是围绕模式中的分配直到它们需要时才发生的事情,并且如果您使用alias链来填充模式,甚至可以构建解析树来扩展嵌套的递归。它是香港专业教育学院发现外壳来执行诸如字符转换之类的工作以及将字符交换为字节值的最快方法。它可以非常快-C语言区域ASCII + <>八进制,最糟糕的情况是7种基本POSIX模式扩展。
mikeserv

1

这不是很好,但是您可以使用:

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

您可能想用$((($ number))来“规范化”该数字以覆盖诸如“ 001”或“ 0x99”之类的数字...这也将覆盖“ 12”和“ 12 + 12”,这可能或可能不理想。
斯特凡Chazelas
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.