关于shell:比较Bash中的数字

Comparing numbers in Bash

我开始学习如何为bash终端编写脚本,但我无法解决如何使比较工作正常进行的问题。我使用的脚本是:

1
2
3
4
5
6
7
8
9
10
11
12
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大于10000,1大于09

如何将数字转换为类型以进行真正的比较?


在bash中,您应该在算术上下文中执行检查:

1
2
3
if (( a > b )); then
    ...
fi

对于不支持(())的posix shell,可以使用-lt-gt

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

您可以获得与help test的比较运算符的完整列表。


简单明了

1
2
3
4
5
6
7
8
#!/bin/bash

a=2462620
b=2462620

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

如果您想在bash脚本编写的美妙世界中获得更多的数字对比,您可以查看这个作弊表。

很快,整数只能与以下项进行比较:

1
2
3
4
5
6
-eq # equal
-ne # not equal
-lt # less than
-le # less than or equal
-gt # greater than
-ge # greater than or equal


还有一件事有些人可能不知道:

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

此代码将打印出ab中的最小数字。


在bash中,我更喜欢这样做,因为它更倾向于将自己定位为一个条件操作,而不是使用更多是算术的(( ))

1
[[ N -gt M ]]

除非我做一些复杂的事情

1
(( (N + 1) > M ))

但每个人都有自己的偏好。可悲的是,有些人强加他们的非官方标准。

更新:

实际上,您也可以这样做:

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

它允许你添加一些你可以用[[ ]]做的事情,除了算术之外。


此代码还可以比较浮动。它使用的是awk(它不是纯bash),但是这不应该是问题,因为awk是一个标准的posix命令,很可能是默认情况下随操作系统提供的。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
$ 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 $?

要缩短使用时间,请使用以下功能:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
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
2
3
4
5
6
7
8
9
10
11
12
13
#!/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


我通过使用一个小函数将版本字符串转换为可以比较的纯整数值来解决这个问题:

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

这有两个重要的假设:

  • 输入是"普通semver字符串"
  • 每部分在0-999之间
  • 例如

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

    示例测试npm命令是否满足最低要求…

    1
    2
    3
    4
    5
    6
    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