比较Bash中的数字

adv*_*013 462 bash shell numeric

我开始学习为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;
Run Code Online (Sandbox Code Playgroud)

我遇到的问题是它比较了第一个数字的数字,即9大于10000,但1大于09

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

jor*_*anm 782

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

if (( a > b )); then
    ...
fi
Run Code Online (Sandbox Code Playgroud)

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

if [ "$a" -gt "$b" ]; then
    ...
fi
Run Code Online (Sandbox Code Playgroud)

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

  • @ advert2013你不应该用零前缀数字.零前缀数字是bash中的八进制数 (7认同)
  • 正如@jordanm所说,"$ a"-gt"$ b"`是正确的答案.这是一个很好的测试运算符列表:[Test Constructs](http://tldp.org/LDP/abs/html/comparison-ops.html). (7认同)
  • 请注意`test`是一个程序,因为`[`.所以`help test`给出了相关的信息.要找出内置插件(`[[`和`((`)你应该使用`help bash`并导航到那个部分. (7认同)
  • 算术表达式很棒,但操作数被视为 [表达式](https://unix.stackexchange.com/questions/482577/bash-arithmetic-expansion-seems-to-be-prone-to-injection-attacks)。 (2认同)
  • @AaronFranke bash 中的数学仅适用于整数,它不适用于浮点或小数。 (2认同)
  • @svebert 总是引用它们是一个很好的做法,但如果它们总是包含整数,那并没有真正的区别。 (2认同)

Dan*_*ncă 152

干净利落

#!/bin/bash

a=2462620
b=2462620

if [ "$a" -eq "$b" ];then
  echo "They're equal";
fi
Run Code Online (Sandbox Code Playgroud)

如果你想要在Bash Scripting的精彩世界中进行更多的数字比较,你可以查看这个备忘单.

简而言之,整数只能与以下内容进行比较:

-eq # equal
-ne # not equal
-lt # less than
-le # less than or equal
-gt # greater than
-ge # greater than or equal
Run Code Online (Sandbox Code Playgroud)

  • 如果使用双括号,则不需要引号:`if [[ $a -eq $b ]];then` (10认同)
  • 您链接的很棒的备忘单,之前没有找到 - 现在 bash 不再那么神奇和不可预测了 - 谢谢! (3认同)
  • @derHugo 引号是可选的。Gilles 对于何时使用它们有更好的解释 https://unix.stackexchange.com/a/68748/50394 (2认同)

Ale*_*-A. 36

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

echo $(( a < b ? a : b ))
Run Code Online (Sandbox Code Playgroud)

这段代码将打印数量最少出ab

  • @konsolebox只是我,或者5和5中最小的数字是5? (82认同)
  • 这不是真的.如果`a == b`,它也会打印`b`. (4认同)
  • 你的陈述含糊不清.即使应用这样的命令也不行:`echo"较小的数字是$((a <b?a:b))." (4认同)
  • 他所说的是,如果`a == b`,'a <b`仍然是正确的.我不知道巴什条件的所有变幻莫测,但几乎可以肯定这会产生影响. (4认同)
  • @bikemule不,他不是这么说的.如果`a == b`,那么`a <b`的计算结果为false,这就是它打印`b`的原因. (4认同)

kon*_*box 19

在Bash中,我更喜欢这样做,因为它更像是一个条件操作,而不像使用(( ))更多的算术.

[[ N -gt M ]]
Run Code Online (Sandbox Code Playgroud)

除非我做复杂的事情

(( (N + 1) > M ))
Run Code Online (Sandbox Code Playgroud)

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

更新:

你其实也可以这样做:

[[ 'N + 1' -gt M ]]
Run Code Online (Sandbox Code Playgroud)

这允许你添加[[ ]]除了算术之外你可以做的其他事情.

  • 这似乎意味着`[[]]`强制算术上下文如`(())`,其中`N`被视为`$ N`,但我不认为这是正确的.或者,如果这不是意图,"N"和"M"的使用令人困惑. (3认同)

jia*_*ian 16

一站式解决方案。

a=2
b=1
[[ ${a} -gt ${b} ]] && echo "true" || echo "false"
Run Code Online (Sandbox Code Playgroud)

gt 参考:https://www.gnu.org/software/bash/manual/html_node/Bash-Conditional-Expressions.html

&&参考:https ://www.gnu.org/software/bash/manual/html_node/Shell-Arithmetic.html

[[...]]构造参考:https://www.gnu.org/software/bash/manual/bash.html#index-_005b_005b

${}参考:https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02 (2.6.2)

参数扩展的格式如下:

${表达式}

其中表达式由匹配“}”之前的所有字符组成。任何在带引号的字符串中由 或 转义的“}”,以及嵌入式算术扩展、命令替换和变量扩展中的字符,在确定匹配的“}”时不应进行检查。

参数扩展的最简单形式是:

${参数}


LC-*_*ist 7

如果您还想使用浮点数,则括号内容(例如,[[ $a -gt $b ]]or (( $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
Run Code Online (Sandbox Code Playgroud)

您可以在 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
Run Code Online (Sandbox Code Playgroud)

如果您想检查数字变量(整数与否)是否在数字范围内,这会很有帮助。


Van*_*las 5

此代码还可以比较浮点数。它使用的是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 $?
Run Code Online (Sandbox Code Playgroud)

为了使它更短使用,请使用以下功能:

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
Run Code Online (Sandbox Code Playgroud)


小智 5

如果你有浮点数,你可以写一个函数然后使用它。例如,

#!/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
Run Code Online (Sandbox Code Playgroud)