我正在构建一个函数,该函数将计算给定电流强度、距离(以英尺为单位)和允许电压降所需的电线规格。
我可以计算给定这些值的“圆形密耳”,并由此得到AWG 要求。我开始建立一个大型if
elif
声明来将圆密耳与其受人尊敬的规格进行比较,但我相信case
这是正确的工具。
我还没有找到任何用于比较数字的案例示例,所以我想知道是否可以执行如下操作:
what.gauge () {
let cmils=11*2*$1*$2/$3
let amils=17*2*$1*$2/$3
case $cmils in
320-403)
cawg="25 AWG"
;;
404-509)
cawg="24 AWG"
;;
510-641)
cawg="23 AWG"
;;
etc...
}
答案1
POSIX 外壳
由于您正在寻找算术测试并且 case 不进行算术运算,因此if-then
似乎是自然的方法:
if [ "$cmils" -lt 320 ]
then
cawg="??"
elif [ "$cmils" -le 403 ]
then
cawg="25 AWG"
elif [ "$cmils" -le 509 ]
then
cawg="24 AWG"
elif [ "$cmils" -le 641 ]
then
cawg="23 AWG"
fi
仅重击
我更喜欢便携式解决方案,但有些人喜欢 bash 的算术语法:
if ((cmils < 320))
then
cawg="??"
elif ((cmils <= 403))
then
cawg="25 AWG"
elif ((cmils <= 509))
then
cawg="24 AWG"
elif ((cmils <= 641))
then
cawg="23 AWG"
fi
它比 POSIX 语法更强大,但也更脆弱。要了解原因,请在设置后尝试此代码cmils=cmils
。
答案2
case $cmils in
3[2-9][0-9]|40[0-3])
cawg="25 AWG"
;;
40[4-9]|4[1-9][0-9]|50[0-9])
cawg="24 AWG"
;;
51[0-9]|6[0-3][0-9]|64[01])
cawg="23 AWG"
;;
答案3
正如其他人所说,case
不支持比较运算符,只支持全局模式匹配。
但是,您可以创建一组 if/elif/fi 语句看更像是一个 case 语句,但格式不同。例如,根据 John1024 的回答:
if [ "$cmils" -lt 320 ]; then cawg='??'
elif [ "$cmils" -le 403 ]; then cawg='25 AWG'
elif [ "$cmils" -le 509 ]; then cawg='24 AWG'
elif [ "$cmils" -le 641 ]; then cawg='23 AWG'
fi
甚至:
[ "$cmils" -ge 320 ] && [ "$cmills" -le 403 ] && cawg='25 AWG'
[ "$cmils" -ge 404 ] && [ "$cmills" -le 509 ] && cawg='24 AWG'
[ "$cmils" -ge 510 ] && [ "$cmills" -le 641 ] && cawg='23 AWG'
笔记:与使用 的任何内容不同elif
,此变体的缺点是至少运行每行的第一个测试。elif
在任何测试评估为 true 后,使用将跳过所有剩余测试。您可以将类似的内容放入函数中并&& return
在设置后添加cawg
。
我个人认为其中任何一个都更具可读性(没有所有额外的换行和交替缩进使事情变得混乱),但对于这个特定的编码风格/缩进问题,意见有很大不同:)
由于所有内容都排列在相同(或非常接近)的列上,因此也可以更轻松地进行复制、粘贴和编辑。当使用一个真正的编辑器时,这是很好的。
答案4
您可以将值映射到范围,然后在语句中使用该范围的索引号case
:
cmil_limits=(320 404 510 642)
index=0
for limit in "${cmil_limits[@]}"
do
if [ "$cmils" -lt "$limit" ]
then
break
fi
((index++))
done
case "$index" in
0) # < 320
cawg="??"
;;
1) # 320-403
cawg="25 AWG"
;;
2) # 404-509
cawg="24 AWG"
;;
3) # 510-641
cawg="23 AWG"
;;
4) # > 641
cawg="??"
;;
esac
如果$cmils
小于 320,我们将for
在第一次迭代时跳出循环,使用index=0
.如果 $cmils
is ≮ 320 (即 is ≥ 320),我们递增index
(→ 1
) 并继续下一次迭代。然后,如果$cmils
is < 404(即 ≤ 403,假设它是整数),我们用 跳出循环index=1
。等等。如果$cmils
is ≮ 642,则它 ≥ 642,因此 > 641,因此我们运行到循环末尾for
并得到index=4
。
这样做的优点是它将截止值保持在一起,全部在同一行,并且您不必维护冗余数字(例如,您当前的代码和另一个答案的代码都列出了 403和404,同时都是509和510——这是多余的,如果数字发生变化,维护工作就会更多。我不知道这是否是现实世界的担忧。)
cmil_limits
是一个数组。 bash、ksh 和其他一些 shell 支持数组,但其他一些 shell 不支持。如果您需要在不支持数组的 shell 中执行类似的操作,您可以将列表直接放入语句中for
:
for limit in 320 404 510 642
do
︙
或者使用 shell 的参数列表作为数组:
set -- 320 404 510 642
for limit in "$@"
do
︙
有些 shell 允许您缩写上面的内容:
set -- 320 404 510 642
for limit
do
︙
((…))
算术也是一种bashism(正如let
声明所述)。如果您需要在不支持算术的 shell 中执行类似的操作((…))
,您可以替换
((index++))
语句(增加index
)与
index=$(expr "$index" + 1)
请注意,之前和之后的空格+
是必需的。