Comparing numbers in Bash

2018-12-31 14:38发布

I'm starting to learn about writing scripts for the bash terminal, but I can't work out how to get the comparisons to work properly. The script I'm using is:

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;

The problem I have is that it compares the number from the first digit on, i.e. 9 is bigger than 10000, but 1 is greater than 09

How can I convert the numbers into a type to do a true comparison?

7条回答
笑指拈花
2楼-- · 2018-12-31 15:12

In Bash I prefer doing this as it addresses itself more as a conditional operation unlike using (( )) which is more of arithmetic.

[[ N -gt M ]]

Unless I do complex stuffs like

(( (N + 1) > M ))

But everyone just has their own preferences. Sad thing is that some people impose their unofficial standards.

Update:

You actually can also do this:

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

Which allows you to add something else which you could do with [[ ]] besides arithmetic stuffs.

查看更多
姐姐魅力值爆表
3楼-- · 2018-12-31 15:13

I solved this by using a small function to convert version strings to plain integer values that can be compared:

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

This makes two important assumptions:

  1. Input is a "normal SemVer string"
  2. Each part is between 0-999

For example

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

Example testing whether npm command meets minimum requirement ...

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
查看更多
冷夜・残月
4楼-- · 2018-12-31 15:14

There is also one nice thing some people might not know about:

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

This code will print the smallest number out of a and b

查看更多
余生请多指教
5楼-- · 2018-12-31 15:25

In bash, you should do your check in arithmetic context:

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

For POSIX shells that don't support (()), you can use -lt and -gt.

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

You can get a full list of comparison operators with help test.

查看更多
还给你的自由
6楼-- · 2018-12-31 15:26

This code can also compare floats. It is using awk (it is not pure bash), however this shouldn't be a problem, as awk is a standard POSIX command that is most likely shipped by default with your operating system.

$ 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 $?

To make it shorter for use, use this function:

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
查看更多
呛了眼睛熬了心
7楼-- · 2018-12-31 15:28

Plain and simple

#!/bin/bash

a=2462620
b=2462620

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

You can check out this cheatsheet if you want more number comparsions in the wonderful world of Bash Scripting.

Shortly, integers can only be compared with:

-eq # equal
-ne # not equal
-lt # less than
-le # less than or equal
-gt # greater than
-ge # greater than or equal
查看更多
登录 后发表回答