bash での 10 進数の比較

bash での 10 進数の比較

今朝、bash で 2 つの 10 進数を比較する方法について検索したところ、次の回答にたどり着きました。シェルスクリプトで浮動小数点数と比較する方法ただし、これには含まれませんこの答えはここにあります:

$ [[ ((3.56 < 2.90)) ]]; echo $?
1
$ [[ ((3.56 < 4.90)) ]]; echo $?
0

その回答が低評価されていること、そしてそれがある種の異常なバシズムのように見えることを考慮すると、この算術評価は正確性に関して信頼できるのでしょうか?

答え1

bash浮動小数点数を理解しません。マニュアルページのセクション
を引用しますbash算術評価:

評価は固定幅の整数で行われます[…]。

したがって、((3 < 4))または は((3 < 2))実際に正しい算術式です。次のように入力できます。

$ echo "$((3 < 4)) -- $((3 < 2))"

出力:1 -- 0

ただし、$ echo $((3.3 < 3.6))構文エラー メッセージが返されます。例では、実際に文字列を比較しています。したがって、次の例をご覧ください。

$ [[ ((3.56 < 04.90)) ]]; echo $?

出力:1

答え2

内部は[[...]] <文字列比較用です。

したがって[[ 3.56 < 2.90 ]]、 or[[ (3.56 < 2.90) ]]または[[ ((3.56 < 2.90)) ]]or ... は、文字列を単に語彙的に文字列と[[ (((3.56 < 2.90))) ]]比較するだけです(語彙的には、たとえばより大きいです)。3.562.90310

整数の比較の場合は、[[ 3 -lt 2 ]]またはです(( 3 < 2 ))。浮動小数点の比較が必要な場合は、ksh93zshまたは、またはyashのような外部ユーティリティが必要です。これは実行できません。awkperlbash

たとえば、次のような関数を定義できます。

compare() (IFS=" "
  exec awk "BEGIN{if (!($*)) exit(1)}"
)

たとえば次のように使用できます:

if compare '1.5*10 < 1e3'; then
  echo less
fi

あるいは、それに関しても:

if compare '"bar" < "foo"'...

文字列の比較を行います。

外部から提供された制御されていないデータをその関数に渡さないでください。compareそうしないと、コマンド インジェクションの脆弱性が発生します (データはawkコードとして解釈され、たとえばawkそれを使用してコマンドを実行できますsystem())。

関連情報