我试图在Bash脚本中划分两个图像宽度,但Bash给我0作为结果:

RESULT=$(($IMG_WIDTH/$IMG2_WIDTH))

我确实研究了Bash指南,我知道我应该使用bc,在互联网上的所有例子中,他们都使用bc。在echo中,我试图把同样的东西放在我的SCALE中,但它不起作用。

以下是我在教程中找到的例子:

echo "scale=2; ${userinput}" | bc 

我怎么能让巴斯给我0.5这样的浮点数呢?


当前回答

作为bc的替代方案,您可以在脚本中使用awk。

例如:

echo "$IMG_WIDTH $IMG2_WIDTH" | awk '{printf "%.2f \n", $1/$2}'

在上面,“%.”2f”告诉printf函数返回一个小数点后两位的浮点数。我使用echo将变量管道作为字段,因为awk对它们正常操作。“$1”和“$2”表示输入awk的第一个和第二个字段。

你可以将结果存储为其他变量,使用:

RESULT = `echo ...`

其他回答

你不能。Bash只处理整数;您必须委托给bc之类的工具。

虽然在Bash中不能使用浮点除法,但可以使用定点除法。你所要做的就是把整数乘以10的次方,然后把整数部分除掉,用取模运算得到小数部分。根据需要舍入。

#!/bin/bash

n=$1
d=$2

# because of rounding this should be 10^{i+1}
# where i is the number of decimal digits wanted
i=4
P=$((10**(i+1)))
Pn=$(($P / 10))
# here we 'fix' the decimal place, divide and round tward zero
t=$(($n * $P / $d + ($n < 0 ? -5 : 5)))
# then we print the number by dividing off the interger part and
# using the modulo operator (after removing the rounding digit) to get the factional part.
printf "%d.%0${i}d\n" $(($t / $P)) $(((t < 0 ? -t : t) / 10 % $Pn))

对于那些试图用公认的答案计算百分比,但失去精度的人:

如果你运行这个:

echo "scale=2; (100/180) * 180" | bc

你只能得到99.00,这就失去了精确度。

如果你这样运行:

echo "result = (100/180) * 180; scale=2; result / 1" | bc -l

现在你得到99.99。

因为你只在打印的时候缩放。

参考此处

您需要多精确的输出?如果你的用例已经可以接受通过bin的近似值,你甚至可以更进一步,利用POSIX退出码[0:256)(所有其他整数修改回该范围)。

在gawk/nawk/mawk-1中,它已经给了我epoch秒到整数级别,但我想扩展它以提取近毫秒的精度,但不是过分迂迂的,我在POSIX shell中运行这个命令

exit $(( 10#` gdate +%5N ` * 256 / 100000 ))

直接分配一个表示0的5位整数。将gnu-date的XXXXXX输出到256个bin中的1个,然后在awk获得system()调用的退出码(即所选的bin #)后撤销这256个bin。我发现这种方法比使用完整的getline调用开销更低。

该方法还直接将输出捕获到POSIX退出码中,而不是打印出一个额外的终端。

(如果以这种方式编写,shell算术自动将其转换为整数而不是* 0.0256)。把它们放在awk函数中,就像这样。10#强制以10为基数,以防止posix shell将“01733”解释为八进制数。

function msecs() {     # n x 2**-8 = n divided by 256

    return 2^-8 * \
           system( "exit \44\50\50 "      \
                   " 10\43\140 gdate \53"  \
                   "%5N\140 \52 " \
                   "256 \57 100000 \51\51" )
}

对于我自己的代码,我应用了另外0.6%的理发来考虑shell开销。

如果你找到了你喜欢的变体,你也可以把它包装到一个函数中。

这里我将一些bashism包装到div函数中:

一个衬套:

function div { local _d=${3:-2}; local _n=0000000000; _n=${_n:0:$_d}; local _r=$(($1$_n/$2)); _r=${_r:0:-$_d}.${_r: -$_d}; echo $_r;}

或多行:

function div {
  local _d=${3:-2}
  local _n=0000000000
  _n=${_n:0:$_d}
  local _r=$(($1$_n/$2))
  _r=${_r:0:-$_d}.${_r: -$_d}
  echo $_r
}

现在你得到了这个函数

div <dividend> <divisor> [<precision=2>]

然后像这样使用它

> div 1 2
.50

> div 273 123 5
2.21951

> x=$(div 22 7)
> echo $x
3.14

更新 我添加了一个小脚本,为您提供了bash的基本浮点数操作:

用法:

> add 1.2 3.45
4.65
> sub 1000 .007
999.993
> mul 1.1 7.07
7.7770
> div 10 3
3.
> div 10 3.000
3.333

这里是脚本:

#!/bin/bash
__op() {
        local z=00000000000000000000000000000000
        local a1=${1%.*}
        local x1=${1//./}
        local n1=$((${#x1}-${#a1}))
        local a2=${2%.*}
        local x2=${2//./}
        local n2=$((${#x2}-${#a2}))
        local n=$n1
        if (($n1 < $n2)); then
                local n=$n2
                x1=$x1${z:0:$(($n2-$n1))}
        fi
        if (($n1 > $n2)); then
                x2=$x2${z:0:$(($n1-$n2))}
        fi
        if [ "$3" == "/" ]; then
                x1=$x1${z:0:$n}
        fi
        local r=$(($x1"$3"$x2))
        local l=$((${#r}-$n))
        if [ "$3" == "*" ]; then
                l=$(($l-$n))
        fi
        echo ${r:0:$l}.${r:$l}
}
add() { __op $1 $2 + ;}
sub() { __op $1 $2 - ;}
mul() { __op $1 $2 "*" ;}
div() { __op $1 $2 / ;}