web-dev-qa-db-ja.com

bashの変数との浮動小数点比較

浮動小数点変数を整数と比較したい。これはbashで行うには最適ではないことは知っていますが、スクリプト全体はすでにbashで書かれています。 $ numberは任意の整数です。 50以下の場合、output1が必要です。他のすべての場合は、他の変数kの出力が必要です。これは私がこれまでに持っているものです:

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

Test = 0.43で試してみると、最初のループは機能しません。整数と浮動小数点の比較に関係していると思いますが、機能させることはできません。

私が不足しているものは何ですか?

PS:this [0.43: command not foundは端末が出力するものです。

23
user1983400

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に準拠していません。

44
user000001

昔の質問のようなものですが、追加の答えがあります。

高精度の電卓(bcまたはdc)へのパイピングは機能しますが、これらの電卓はbashに組み込まれていないため、フォークと余分なプロセスが必要になります。 ISに組み込まれているものの1つは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

ここで考慮すべきことがいくつかあります。

  • 関数を[[[と名付けました。好きな名前を付けることができます。 ntestまたはmynumericcomparisonまたは[[[
  • printfはbash内の内部関数であるため、パス上にあるにもかかわらず、フォークの費用はかかりません。
  • 現状では、この関数は999.999までの数字をサポートしています。より高い数値(またはより高い精度)が必要な場合は、printf形式を調整します。
  • caseステートメント内の各変数の先頭にある10#は、ゼロが埋め込まれた数値が8進数として解釈される可能性があるため、10を基数とする比較を強制します。

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

10
ghoti