2013-03-05 54 views
23

我想将浮点变量与整数进行比较。 我知道这不是最好的与bash,但我的整个脚本已经写在bash中。 $ number可以是任何整数。如果它低于或等于50,我想要output1,对于其他所有其他我想用另一个变量k输出。这是我到目前为止:与bash中的变量进行浮点比较

number=43 
test=$(echo "scale=2; $number/50" | bc -l) 
echo "$test" 
for k in {1..5} 
do 
    if ["$test" -le 1] 
    then echo "output" 

    elif ["$test" -gt $k] 
    then echo "output$k" 
    fi 
done 

如果我尝试与测试= 0.43,第一个循环甚至不工作。我认为它与整数和浮点比较有关,但不能使其工作。

我失踪了吗?

PS:此[0.43: command not found是终端输出。

+0

你也可以切换到KSH和使用排版,自动轮。 (这是自1993年以来可用,运作良好) – 2016-09-20 01:04:35

回答

43

Bash无法处理浮游物。管bc代替:

if [ $(echo " $test > $k" | bc) -eq 1 ] 

看到,虽然该错误是因为test命令(即[)前后

它甚至更好,因为你比较喜欢这个号码使用((...))需求空间:

if (($(bc <<< "$test > $k"))) 

在循环中的部分应该是这样的:

if (($(bc <<< "$test <= 1"))) 
then 
    echo "output" 
elif (($(bc <<< "$test > $k"))) 
then 
    echo "output$k" 
fi 

如果关系为假,则关系表达式求值为0;如果关系为真,则关系表达式求值为1 [source]。请注意,这是GNU bc的行为,并不是POSIX compiant。

+1

此外:bash:[:1.3:预期的整数表达式将是错误,如果您已正确格式化[]表达式。 + 1 @ user000001 – 2013-03-05 13:18:51

+0

非常感谢!有用。小问题,我正在努力研究。我想第一个要么小于或等于1,要么其他要严格高于k。我可以写(($(bc <<<“$ test <1”&&“$ test = 1”)== 1))或(($(bc <<<“$ test <= 1”)== 1) ))? – user1983400 2013-03-05 15:43:08

+0

第二个是正确的。第一个是正确的,你引用像这样:'(($(bc <<<“$ test <1 && $ test == 1”)== 1))'(也是'==')。有关'bc'中布尔表达式的更多信息,请参见:http://www.gnu.org/software/bc/manual/html_mono/bc.html#SEC12 – user000001 2013-03-05 15:52:15

9

这是一个古老的问题,但它带有一个额外的答案,我认为。

虽然管道连接到更高精度的计算器(bc或dc)可以工作,但这是以fork和额外的过程为代价的,因为这些计算器不是内置到bash中的。但是,内置的一件事是printf。所以,如果你能处理你的号码是小数的具体数量范围内,可以通过“假”浮点比较,具有这样的功能:

#!/usr/bin/env bash 

function [[[() { 
    local LANG=C lhs rhs 
    printf -v lhs '%07.3f' "$1"; lhs=${lhs/./} 
    printf -v rhs '%07.3f' "$3"; rhs=${rhs/./} 
    case "$2" in 
    -lt) return $((! (10#$lhs < 10#$rhs))) ;; 
    -le) return $((! (10#$lhs <= 10#$rhs))) ;; 
    -eq) return $((! (10#$lhs == 10#$rhs))) ;; 
    -ge) return $((! (10#$lhs >= 10#$rhs))) ;; 
    -gt) return $((! (10#$lhs > 10#$rhs))) ;; 
    esac 
} 

number=${1:-43} 
test=$(dc -e "2k $number 50/p") 
echo "$test" 

for k in {1..5}; do 
    if [[[ "$test" -le 1 ]]]; then 
     echo "output" 
    elif [[[ "$test" -gt "$k" ]]]; then 
     echo "output $k" 
    fi 
done 

几件事情需要考虑。

  • 我已经命名功能[[[是可爱的。你可以随便命名。 ntestmynumericcomparison或甚至[[[
  • printf是bash中的一个内部函数,所以尽管它在你的路径上,但它并不会花费一个分支。
  • 就目前而言,该功能支持最高999.999的数字。如果您需要更高的数字(或更高精度),请调整printf格式。
  • case声明中每个变量开始处的10#强制比较发生在基数10,因为零填充的数字可能会被解释为八进制数。

参见:http://mywiki.wooledge.org/BashFAQ/022

+1

这看起来相当不错,但为了复制粘贴,我将'printf'格式设置为更明智的选项(漂浮可能很长,并且保持低精度不会使此函数更快)。 – 2016-01-12 08:05:34