在 BASH 数学脚本中使用 Python 的替代方法

Alternative to using Python in a BASH script for math

我正在编写 BASH 脚本。我有一个设置为以下代码的变量:

VAR="$(python -c "print (-$STEP+0.25) > ($OLD_OUTPUT_POWER - $NEW_OUTPUT_POWER) > (-$STEP-0.25)")"

其中STEP为10-1之间的整数,OLD_OUTPUT_POWERNEW_OUTPUT_POWER为小数(即:-14.3498306270)。我熟悉 Python,并希望在 BASH 中严格执行以下操作:

if ((-$STEP+0.25) > ($OLD_OUTPUT_POWER - $NEW_OUTPUT_POWER) > (-$STEP-0.25)); then
    blah blah

基本上如果是真的,那就去做。

我现在的做法是这样的:

VAR="$(python -c "print (-$STEP+0.25) > ($OLD_OUTPUT_POWER - $NEW_OUTPUT_POWER) > (-$STEP-0.25)")"

if [[ $VAR == "True" ]]; then
    echo "True"
fi

但是我希望能够在不使用 Python 的情况下做到这一点。有什么想法吗?

提前致谢:)

如果小数点很重要,则使用 bc 否则使用 bash 扩展名 $((ANARITHMETICEXPRESSION)).

shell 本身没有进行浮点运算的可移植方法。您将需要求助于外部程序。

您可以使用 AWK 而不是 Python,它的开销明显较小。请注意,它不理解 Python 花哨的 x < y < z 语法,因此您必须将其重写为 x < y && y < z。您可以定义这个 Bash 函数。

## usage: is_between VALUE UPPER LOWER
##
## Checks whether VALUE is truly between UPPER and LOWER.
##
function is_between {
    awk "BEGIN { exit(!( <  &&  < )); }"
}

它将 return 通过其退出状态给出答案,因此可以直接在条件语句中使用。例如:

value=3.15
lower=3.14
upper=3.16

if is_between $value $lower $upper
then
    echo "$value is in ($lower, $upper)"
else
    echo "$value is not in ($lower, $upper)"
fi

我写了一个小基准。请注意,我实际上是在比较整数,而不是实数,因此我可以与 shell 内置函数进行比较。

#!/bin/sh -eu

what=
if [ ${#} -gt 0 ]
then
    what=
fi

case $what in
    awk)
        function is_between {
            awk "BEGIN { exit(!( <  &&  < )); }"
        }
        ;;
    python)
        function is_between {
            python -c "import sys; sys.exit(not ( <  < ));"
        }
        ;;
    *)
        # This one only works for integers!
        function is_between {
            return $((!( <  &&  < )))
        }
        ;;
esac

i=0
count=0
while [ $i -lt 1000 ]
do
    value="$RANDOM"
    lower="$RANDOM"
    upper="$RANDOM"
    if is_between $value $lower $upper
    then
        count=$(($count + 1))
    fi
    i=$(($i + 1))
done
echo "$count values were in between"

这是我的计时结果:

$ time ./test.sh
152 values were in between

real    0m0.055s
user    0m0.053s
sys 0m0.000s


$ time ./test.sh python
146 values were in between

real    0m33.354s
user    0m27.570s
sys 0m4.047s


$ time ./test.sh awk
157 values were in between

real    0m5.486s
user    0m3.503s
sys 0m0.723s

如您所见,差异非常显着……