Bashでの数値の比較


546

私はbashターミナル用のスクリプトの作成について学び始めていますが、比較を適切に機能させる方法を見つけることができません。私が使用しているスクリプトは次のとおりです。

echo "enter two numbers";
read a b;

echo "a=$a";
echo "b=$b";

if [ $a \> $b ];
then 
    echo "a is greater than b";
else
    echo "b is greater than a";
fi;

問題は、最初の桁から数を比較することです。つまり、9は10より大きいが、1は09より大きい。

真の比較を行うために、数値を型に変換するにはどうすればよいですか?


1
基本的な読み物:BashFAQ
エドゥアールロペス

6
ところで、bashではセミコロンはステートメントの区切り文字であり、改行であるステートメントの終了文字ではありません。したがって、行に1つのステートメントしかない場合は;、行末のatは不要です。害はありません。キーストロークの無駄です(セミコロンの入力を楽しんでいない限り)。
cdarke 2013

6
小数に先行ゼロの数字を強制するには、次の10#$numberように、number=09; echo "$((10#$number))"意志出力9しながら、echo $((number))エラー「ベースの値が大きすぎる」を生成します。
追って通知があるまで一時停止。

4
答えはすべて正しいことを教えてくれますが、間違っている>わけではありません。オペレーターが[コマンドで行うことは、2つの文字列を並べ替える順序を比較することです。数値として並べ替える順序ではありません。詳細については、をご覧くださいman test
user3035772

回答:


879

bashでは、算術コンテキストでチェックを行う必要があります。

if (( a > b )); then
    ...
fi

をサポートしないPOSIXシェルの(())場合は、-ltおよびを使用できます-gt

if [ "$a" -gt "$b" ]; then
    ...
fi

help testまたはで比較演算子の完全なリストを取得できますman test


7
@jordanm "$a" -gt "$b"が言ったように、正しい答えです。ここでは、テストオペレータの良いリストがある:テストの構築
Jeffery Thomas

それは間違いなく機能していますが、1と09を比較して01と09を比較する場合、奇妙な1と09を比較すると、「((:09:value too great for base(error token is "09")」が表示されますが、基本的には解決されています。私の問題はとても感謝しています!
advert2013

8
@ advert2013数字の前にゼロを付けるべきではありません。プレフィックスがゼロの数字はbashでは8進数です
Aleks-Daniel Jakimenko-A。

8
それtestがプログラムであることに注意してください[。それhelp testに関する情報を提供します。組み込み([[および(()の機能を確認するにはhelp bash、その部分を使用してナビゲートする必要があります。
RedX 2015年

1
算術式は素晴らしいですが、オペランドはとして扱われます
x-yuri 2018

180

簡潔でシンプル

#!/bin/bash

a=2462620
b=2462620

if [ "$a" -eq "$b" ];then
  echo "They're equal";
fi

Bashスクリプトのすばらしい世界でさらに多くの比較が必要な場合は、このチートシートをチェックしてください。

簡単に言えば、整数は以下とのみ比較できます。

-eq # equal
-ne # not equal
-lt # less than
-le # less than or equal
-gt # greater than
-ge # greater than or equal

私はあなたの他の変更を元に戻しました-二重引用符"$a""$b"は必須ではありませんが、それらは良い習慣です。中括弧は、ここでは何の役にも立ちません。
トムフェネック2017

1
あなたがリンクした素晴らしいチートシートは以前には見つかりませんでした-今ではbashはそれほど魔法のようで予測不可能ではないようです-ありがとうございます!
Ilja

見積もりは"必須[ $a -eq $b ]ですか、それとも問題ありませんか?
derHugo 2018

1
@derHugoの引用符はオプションです。Gillesがunix.stackexchange.com/a/68748/50394をいつ
Daniel AndreiMincăAug


38

一部の人が知らないかもしれない1つの良いこともあります。

echo $(( a < b ? a : b ))

このコードは、最小数を出力しab


5
それは真実ではない。また、印刷されbますa == b
konsolebox 2013

88
@konsoleboxは私だけですか、それとも5と5のうち最小の数は5ですか?
Aleks-Daniel Jakimenko-A。

4
あなたの発言は曖昧です。このようなコマンドを適用しても機能しません:echo "The smaller number is $(( a < b ? a : b ))."
konsolebox

4
彼が言っていることa < bは、それでもまだ真実ですa == b。私はバッシュの条件付きの気まぐれのすべてを知っているわけではありませんが、これが違いを生む状況はほぼ確実にあります。
–bikemule

4
@bikemuleいいえ、彼はそれを言っていません。の場合はa == ba < bfalseと評価されます。そのため、が出力されますb
mapeters 2017

21

Bashでは、(( ))これは算術演算を使用するのとは異なり、条件演算として自身に対処するため、これを行うことを好みます。

[[ N -gt M ]]

私が複雑なことをしない限り

(( (N + 1) > M ))

しかし、誰もが自分の好みを持っています。悲しいことに、一部の人々は非公式の基準を課しています。

更新:

実際にこれを行うこともできます:

[[ 'N + 1' -gt M ]]

これにより[[ ]]、算術演算以外にもできることを追加できます。


3
これは、の[[ ]]ような算術コンテキストを強制することを意味するようですが(( ))、はのようにN扱われますが$N、私はそれが正しいとは思いません。または、それが意図されていなかった場合、Nおよびの使用Mは混乱を招きます。
Benjamin W.

@BenjaminW。これはChetからの確認が必要ですが、-eq、-ne、-lt、-le、-gt、および-geは、「算術テスト」の形式(ドキュメント化)であり、オペランドが次のように算術式の影響を受けることを意味します。まあ..
konsolebox 19/11/24

これに戻って来るためのおかげで、あなたは完全に右としているようマニュアル「で使用した場合:明確に述べ[[コマンド、Arg1およびArg2[...]算術式として評価されています」。
ベンジャミン

私はNUMBER=0.0; while [[ "$NUMBER" -lt "1.0" ]]; doそれを持っていますbash: [[: 0.0: syntax error: invalid arithmetic operator (error token is ".0")
アーロン・フランケ

@AaronFranke Bash演算は小数をサポートしていません。
konsolebox

6

このコードは、floatを比較することもできます。これはawk(純粋なbashではありません)を使用していますが、awkはオペレーティングシステムにデフォルトで付属している可能性が高い標準のPOSIXコマンドであるため、これは問題にはなりません。

$ awk 'BEGIN {return_code=(-1.2345 == -1.2345) ? 0 : 1; exit} END {exit return_code}'
$ echo $?
0
$ awk 'BEGIN {return_code=(-1.2345 >= -1.2345) ? 0 : 1; exit} END {exit return_code}'
$ echo $?
0
$ awk 'BEGIN {return_code=(-1.2345 < -1.2345) ? 0 : 1; exit} END {exit return_code}'
$ echo $?
1
$ awk 'BEGIN {return_code=(-1.2345 < 2) ? 0 : 1; exit} END {exit return_code}'
$ echo $?
0
$ awk 'BEGIN {return_code=(-1.2345 > 2) ? 0 : 1; exit} END {exit return_code}'
$ echo $?

使用するために短くするには、次の関数を使用します。

compare_nums()
{
   # Function to compare two numbers (float or integers) by using awk.
   # The function will not print anything, but it will return 0 (if the comparison is true) or 1
   # (if the comparison is false) exit codes, so it can be used directly in shell one liners.
   #############
   ### Usage ###
   ### Note that you have to enclose the comparison operator in quotes.
   #############
   # compare_nums 1 ">" 2 # returns false
   # compare_nums 1.23 "<=" 2 # returns true
   # compare_nums -1.238 "<=" -2 # returns false
   #############################################
   num1=$1
   op=$2
   num2=$3
   E_BADARGS=65

   # Make sure that the provided numbers are actually numbers.
   if ! [[ $num1 =~ ^-?[0-9]+([.][0-9]+)?$ ]]; then >&2 echo "$num1 is not a number"; return $E_BADARGS; fi
   if ! [[ $num2 =~ ^-?[0-9]+([.][0-9]+)?$ ]]; then >&2 echo "$num2 is not a number"; return $E_BADARGS; fi

   # If you want to print the exit code as well (instead of only returning it), uncomment
   # the awk line below and comment the uncommented one which is two lines below.
   #awk 'BEGIN {print return_code=('$num1' '$op' '$num2') ? 0 : 1; exit} END {exit return_code}'
   awk 'BEGIN {return_code=('$num1' '$op' '$num2') ? 0 : 1; exit} END {exit return_code}'
   return_code=$?
   return $return_code
}

$ compare_nums -1.2345 ">=" -1.2345 && echo true || echo false
true
$ compare_nums -1.2345 ">=" 23 && echo true || echo false
false

1
私は大きな数をbash扱っており、それらを適切に比較できません(をお試しくださいif (( 18446744073692774399 < 8589934592 )); then echo 'integer overflow'; fiawkチャーム(if awk "BEGIN {return_code=(18446744073692774399 > 8589934592) ? 0 : 1; exit} END {exit return_code}"; then echo 'no integer overflow'; fi)のように機能します。
jaume 2017年

3

フロートがある場合は、関数を記述して使用できます。

#!/bin/bash

function float_gt() {
    perl -e "{if($1>$2){print 1} else {print 0}}"
}

x=3.14
y=5.20
if [ $(float_gt $x $y) == 1 ] ; then
    echo "do stuff with x"
else
    echo "do stuff with y"
fi

3

角かっこ(例:[[ $a -gt $b ]]または(( $a > $b )))は、浮動小数点数も使用する場合には十分ではありません。構文エラーを報告します。浮動小数点数または浮動小数点数を整数と比較する場合は、を使用できます(( $(bc <<< "...") ))

例えば、

a=2.00
b=1

if (( $(bc <<<"$a > $b") )); then 
    echo "a is greater than b"
else
    echo "a is not greater than b"
fi

ifステートメントには複数の比較を含めることができます。例えば、

a=2.
b=1
c=1.0000

if (( $(bc <<<"$b == $c && $b < $a") )); then 
    echo "b is equal to c but less than a"
else
    echo "b is either not equal to c and/or not less than a"
fi

これは、数値変数(整数かどうか)が数値の範囲内にあるかどうかを確認する場合に役立ちます。


これは私にはうまくいきません。私の知る限り、bcコマンドは終了値を返さず、比較が真の場合は「1」を出力します(そうでない場合は「0」を出力します)。私は代わりにこれを書く必要があります:if [ "$(bc <<<"$a > $b") == "1" ]; then echo "a is greater than b; fi
Terje Mikal

@TerjeMikalあなたのコマンドは、どういう意味if [ $(bc <<<"$a > $b") == "1" ]; then echo "a is greater than b"; fiですか?(私はあなたのコマンドが間違って書かれたと思います。)もしそうなら、それもうまくいきます。Bash Calculator(bc)コマンドは、基本的な電卓コマンドです。ここここにいくつかの使用例があります。私のコマンド例がなぜうまくいかなかったのか、私にはわかりません。
LCデータサイエンティスト、

2

小さな関数を使用してバージョン文字列を比較可能なプレーンな整数値に変換することで、これを解決しました。

function versionToInt() {
  local IFS=.
  parts=($1)
  let val=1000000*parts[0]+1000*parts[1]+parts[2]
  echo $val
}

これは、2つの重要な仮定を行います。

  1. 入力は「通常のSemVer文字列」です
  2. 各パーツは0〜999です

例えば

versionToInt 12.34.56  # --> 12034056
versionToInt 1.2.3     # -->  1002003

npmコマンドが最小要件を満たしているかどうかをテストする例...

NPM_ACTUAL=$(versionToInt $(npm --version))  # Capture npm version
NPM_REQUIRED=$(versionToInt 4.3.0)           # Desired version
if [ $NPM_ACTUAL \< $NPM_REQUIRED ]; then
  echo "Please update to npm@latest"
  exit 1
fi

'sort -V'を使用すると、バージョン番号をソートして、次に何をするかを決定できます。次のような比較関数を記述できます。function version_lt(){test "$(printf '%s \ n'" $ @ "| sort -V | head -n 1)" == "$ 1"; そして、次のように使用します:if version_lt $ v1 $ v2; その後...
koem
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.