我可以使用比较运算符吗?

我可以使用比较运算符吗?

我正在构建一个函数,该函数将计算给定电流强度、距离(以英尺为单位)和允许电压降所需的电线规格。

我可以计算给定这些值的“圆形密耳”,并由此得到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.如果 $cmilsis ≮ 320 (即 is ≥ 320),我们递增index(→ 1) 并继续下一次迭代。然后,如果$cmilsis < 404(即 ≤ 403,假设它是整数),我们用 跳出循环index=1。等等。如果$cmilsis ≮ 642,则它 ≥ 642,因此 > 641,因此我们运行到循环末尾for并得到index=4

这样做的优点是它将截止值保持在一起,全部在同一行,并且您不必维护冗余数字(例如,您当前的代码和另一个答案的代码都列出了 403404,同时都是509510——这是多余的,如果数字发生变化,维护工作就会更多。我不知道这是否是现实世界的担忧。)


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)

请注意,之前和之后的空格+是必需的。

相关内容