关于linux:如何测试变量是否是Bash中的数字?

How do I test if a variable is a number in Bash?

我只是不知道如何确定传递给脚本的参数是否是数字。

我只想做这样的事情:

1
test *isnumber* $1 && VAR=$1 || echo"need a number"

有什么帮助吗?


一种方法是使用正则表达式,如:

1
2
3
4
re='^[0-9]+$'
if ! [[ $yournumber =~ $re ]] ; then
   echo"error: Not a number">&2; exit 1
fi

如果该值不一定是整数,请考虑适当地修改regex;例如:

1
^[0-9]+([.][0-9]+)?$

…或者,用符号处理数字:

1
^[+-]?[0-9]+([.][0-9]+)?$


没有bashims(即使在系统v sh中也能工作)。

1
2
3
4
case $string in
    ''|*[!0-9]*) echo bad ;;
    *) echo good ;;
esac

这将拒绝空字符串和包含非数字的字符串,并接受其他所有内容。

负数或浮点数需要做一些额外的工作。一种想法是在第一个"坏"模式中排除-/.,并添加更多包含不适当使用的"坏"模式(?*-*/*.*.*)


以下解决方案也可以用于基本外壳,如Bourne,而不需要正则表达式。基本上,任何使用非数字的数值计算操作都将导致一个错误,在shell中该错误将被隐式地视为错误:

1
"$var" -eq"$var"

如:

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

var=a

if [ -n"$var" ] && ["$var" -eq"$var" ] 2>/dev/null; then
  echo number
else
  echo not a number
fi

你也可以测试美元吗?更明确的操作返回代码:

1
2
3
4
[ -n"$var" ] && ["$var" -eq"$var"] 2>/dev/null
if [ $? -ne 0 ]; then
   echo $var is not number
fi

标准错误的重定向是为了隐藏bash在没有数字的情况下打印出来的"integer expression expected"消息。

注意事项(感谢下面的评论):

  • 带小数点的数字未标识为有效的"数字"
  • 使用[[ ]]而不是[ ]将始终对true进行评估。
  • 大多数非bash shell总是将该表达式计算为true
  • bash中的行为是未记录的,因此可能在没有警告的情况下发生更改。
  • 如果该值包含数字后的空格(例如"1 A")会产生错误,如bash: [[: 1 a: syntax error in expression (error token is"a")
  • 如果该值与var name相同(例如i="i"),则会产生错误,如bash: [[: i: expression recursion level exceeded (error token is"i")


这将测试一个数字是否为非负整数,是否与shell无关(即没有bashims),并且只使用shell内置的:

不正确。

因为第一个答案(下面)允许包含字符的整数,只要第一个不是变量中的第一个。

1
[ -z"${num##[0-9]*}" ] && echo"is a number" || echo"is not a number";

对的。

正如Jilles在他的回答中评论和建议的那样,这是使用shell模式来实现这一点的正确方法。

1
[ ! -z"${num##*[!0-9]*}" ] && echo"is a number" || echo"is not a number";


没有人建议bash的扩展模式匹配:

1
[[ $1 == ?(-)+([0-9]) ]] && echo"$1 is an integer"


我对直接在shell中解析数字格式的解决方案感到惊讶。Shell不太适合这样做,因为它是用于控制文件和进程的DSL。有足够多的数字解析器,下面稍微低一点,例如:

1
2
3
4
5
6
isdecimal() {
  # filter octal/hex/ord()
  num=$(printf '%s'"$1" | sed"s/^0*\([1-9]\)/\1/; s/'/^/")

  test"$num" && printf '%f'"$num">/dev/null 2>&1
}

将"%f"更改为所需的任何特定格式。


我在看答案…意识到没有人想到浮点数(带点)!

使用grep也很好。-e表示扩展regexp-Q表示安静(不回音)-QE是两者的结合。

直接在命令行中测试:

1
2
3
4
5
6
7
8
9
10
11
$ echo"32" | grep -E ^\-?[0-9]?\.?[0-9]+$  
# answer is: 32

$ echo"3a2" | grep -E ^\-?[0-9]?\.?[0-9]+$  
# answer is empty (false)

$ echo".5" | grep -E ^\-?[0-9]?\.?[0-9]+$  
# answer .5

$ echo"3.2" | grep -E ^\-?[0-9]?\.?[0-9]+$  
# answer is 3.2

在bash脚本中使用:

1
2
3
4
5
6
7
8
9
check=`echo"$1" | grep -E ^\-?[0-9]*\.?[0-9]+$`

if ["$check" != '' ]; then    
  # it IS numeric
  echo"Yeap!"
else
  # it is NOT numeric.
  echo"nooop"
fi

要仅匹配整数,请使用以下命令:

1
2
# change check line to:
check=`echo"$1" | grep -E ^\-?[0-9]+$`


只是对@mary的跟进。但因为我没有足够的代表,所以无法将此作为评论发布到该帖子中。不管怎样,我用的是:

1
isnum() { awk -v a="$1" 'BEGIN {print (a == a + 0)}'; }

如果参数是数字,函数将返回"1",否则将返回"0"。这既适用于整数,也适用于浮点。用法如下:

1
2
3
4
5
6
7
n=-2.05e+07
res=`isnum"$n"`
if ["$res" =="1" ]; then
     echo"$n is a number"
else
     echo"$n is not a number"
fi


http://tldp.org/ldp/bash-初学者指南/html/sect__03.html

您还可以使用bash的字符类。

1
2
3
4
5
if [[ $VAR = *[[:digit:]]* ]]; then
 echo"$VAR is numeric"
else
 echo"$VAR is not numeric"
fi

数字包括空格、小数点和浮点数的"e"或"e"。

但是,如果指定了C样式的十六进制数,即"0xffff"或"0xffff",[:digit:]将返回true。这里有一个陷阱,bash允许你做一些类似于"0xaz00"的事情,并且仍然把它作为一个数字来计算(这不是来自GCC编译器的一些奇怪的怪癖,它允许你对16以外的基使用0x符号吗???)

如果您的输入完全不可信,您可能需要在测试它是否是数字之前测试"0x"或"0x",除非您想接受十六进制数字。这将通过以下方式实现:

1
if [[ ${VARIABLE:1:2} ="0x" ]] || [[ ${VARIABLE:1:2} ="0X" ]]; then echo"$VAR is not numeric"; fi


老问题,但我只想强调我的解决方案。这个不需要任何奇怪的贝壳技巧,也不需要依赖那些永远不存在的东西。

1
2
3
4
5
6
if [ -n"$(printf '%s
'"
$var" | sed 's/[0-9]//g')" ]; then
    echo 'is not numeric'
else
    echo 'is numeric'
fi

基本上,它只是从输入中删除所有数字,如果留下一个非零长度的字符串,那么它就不是一个数字。


1
test -z"${i//[0-9]}" && echo digits || echo no no no

${i//[0-9]}用空字符串替换$i值中的任何数字,见man -P 'less +/parameter\/' bash-z检查结果字符串的长度是否为零。

如果还想排除当$i为空时的情况,可以使用以下构造之一:

1
2
test -n"$i" && test -z"${i//[0-9]}" && echo digits || echo not a number
[[ -n"$i" && -z"${i//[0-9]}" ]] && echo digits || echo not a number


1
[[ $1 =~ ^-?[0-9]+$ ]] && echo"number"

别忘了-包括负数!


还不能评论,所以我将添加我自己的答案,这是使用bash模式匹配对glenn jackman答案的扩展。

我最初的需要是识别数字,区分整数和浮点数。函数定义推导为:

1
2
3
4
5
6
7
function isInteger() {
    [[ ${1} == ?(-)+([0-9]) ]]
}

function isFloat() {
    [[ ${1} == ?(-)@(+([0-9]).*([0-9])|*([0-9]).+([0-9]))?(E?(-|+)+([0-9])) ]]
}

我使用单元测试(使用shunit2)来验证我的模式是否按预期工作:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
oneTimeSetUp() {
    int_values="0 123 -0 -123"
    float_values="0.0 0. .0 -0.0 -0. -.0 \
       123.456 123. .456 -123.456 -123. -.456
        123.456E08 123.E08 .456E08 -123.456E08 -123.E08 -.456E08 \
       123.456E+08 123.E+08 .456E+08 -123.456E+08 -123.E+08 -.456E+08 \
       123.456E-08 123.E-08 .456E-08 -123.456E-08 -123.E-08 -.456E-08"

}

testIsIntegerIsFloat() {
    local value
    for value in ${int_values}
    do
        assertTrue"${value} should be tested as integer""isInteger ${value}"
        assertFalse"${value} should not be tested as float""isFloat ${value}"
    done

    for value in ${float_values}
    do
        assertTrue"${value} should be tested as float""isFloat ${value}"
        assertFalse"${value} should not be tested as integer""isInteger ${value}"
    done

}

注:isfloat模式可以修改为对小数点(@(.,)和e符号(@(Ee)更为宽容。我的单元测试只测试整数或浮点值,但不测试任何无效的输入。


我用EXPR。如果尝试向非数字值添加零,则返回非零:

1
2
3
4
5
6
if expr --"$number" + 0 > /dev/null 2>&1
then
    echo"$number is a number"
else
    echo"$number isn't a number"
fi

如果您需要非整数,可能可以使用bc,但我不相信bc具有完全相同的行为。向非数字加零可以得到零,它也返回零的值。也许你可以把bcexpr结合起来。用bc把0加到$number上。如果答案是0,则尝试expr验证$number不是零。


我想试试这个:

1
2
3
4
5
6
printf"%g""$var" &> /dev/null
if [[ $? == 0 ]] ; then
    echo"$var is a number."
else
    echo"$var is not a number."
fi

注意:这将NAN和INF识别为数字。


@charles dufy和其他人已经给出了明确的答案。纯bash解决方案将使用以下内容:

1
2
3
4
5
6
7
string="-12,345"
if [["$string" =~ ^-?[0-9]+[.,]?[0-9]*$ ]]
then
    echo $string is a number
else
    echo $string is not a number
fi

尽管对于实数,在基数点之前没有强制的数字。

为了对浮点数和科学记数法提供更全面的支持(许多C/Fortran或其他语言中的程序将以这种方式导出浮点数),对这一行的有用补充如下:

1
2
3
4
5
6
7
string="1.2345E-67"
if [["$string" =~ ^-?[0-9]*[.,]?[0-9]*[eE]?-?[0-9]+$ ]]
then
    echo $string is a number
else
    echo $string is not a number
fi

因此,如果您要查找任何特定类型,可以使用一种方法来区分数字类型:

1
2
3
4
5
6
7
8
9
10
11
12
13
string="-12,345"
if [["$string" =~ ^-?[0-9]+$ ]]
then
    echo $string is an integer
elif [["$string" =~ ^-?[0-9]*[.,]?[0-9]*$ ]]
then
    echo $string is a float
elif [["$string" =~ ^-?[0-9]*[.,]?[0-9]*[eE]-?[0-9]+$ ]]
then
    echo $string is a scientific number
else
    echo $string is not a number
fi

注:我们可以列出十进制和科学记数法的语法要求,一种是允许逗号作为基数,以及"."。然后我们断言,这样的基点必须只有一个。一个[EE]浮动中可以有两个+/-符号。我从奥鲁的作品中学到了更多的规则,并对"e-1"和"0-0"等不好的字符串进行了测试。下面是我的regex/substring/expr工具,它们似乎支持:

1
2
3
4
5
6
7
8
parse_num() {
 local r=`expr"$1" : '.*\([.,]\)' 2>/dev/null | tr -d '
'
`
 nat='^[+-]?[0-9]+[.,]?$' \
 dot="${1%[.,]*}${r}${1##*[.,]}" \
 float='^[\+\-]?([.,0-9]+[Ee]?[-+]?|)[0-9]+$'
 [["$1" == $dot ]] && [["$1" =~ $float ]] || [["$1" =~ $nat ]]
} # usage: parse_num -123.456

最简单的方法是检查它是否包含非数字字符。将所有数字字符替换为空,并检查长度。如果有长度,就不是数字。

1
2
3
if [[ ! -n ${input//[0-9]/} ]]; then
    echo"Input Is A Number"
fi


因为我最近不得不修改这个,并且最喜欢Karttu的单元测试。我修改了代码并添加了一些其他解决方案,您自己试试看结果:

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
35
36
37
38
39
40
#!/bin/bash

    # N={0,1,2,3,...} by syntaxerror
function isNaturalNumber()
{
 [[ ${1} =~ ^[0-9]+$ ]]
}
    # Z={...,-2,-1,0,1,2,...} by karttu
function isInteger()
{
 [[ ${1} == ?(-)+([0-9]) ]]
}
    # Q={...,-?,-?,0.0,?,?,...} by karttu
function isFloat()
{
 [[ ${1} == ?(-)@(+([0-9]).*([0-9])|*([0-9]).+([0-9]))?(E?(-|+)+([0-9])) ]]
}
    # R={...,-1,-?,-?,0.E+n,?,?,1,...}
function isNumber()
{
 isNaturalNumber $1 || isInteger $1 || isFloat $1
}

bools=("TRUE""FALSE")
int_values="0 123 -0 -123"
float_values="0.0 0. .0 -0.0 -0. -.0 \
   123.456 123. .456 -123.456 -123. -.456 \
   123.456E08 123.E08 .456E08 -123.456E08 -123.E08 -.456E08 \
   123.456E+08 123.E+08 .456E+08 -123.456E+08 -123.E+08 -.456E+08 \
   123.456E-08 123.E-08 .456E-08 -123.456E-08 -123.E-08 -.456E-08"

false_values="blah meh mooh blah5 67mooh a123bc"

for value in ${int_values} ${float_values} ${false_values}
do
    printf"  %5s=%-30s" $(isNaturalNumber $value) ${bools[$?]} $(printf"isNaturalNumber(%s)" $value)
    printf"%5s=%-24s" $(isInteger $value) ${bools[$?]} $(printf"isInteger(%s)" $value)
    printf"%5s=%-24s" $(isFloat $value) ${bools[$?]} $(printf"isFloat(%s)" $value)
    printf"%5s=%-24s
"
$(isNumber $value) ${bools[$?]} $(printf"isNumber(%s)" $value)
done

因此isNumber()包含破折号、逗号和指数符号,因此在整数和浮点数上返回true,而在另一方面,isFloat()在整数值上返回false,isinteger()在浮点数上同样返回false。为了您的方便,所有这些都是一句话:

1
2
3
4
isNaturalNumber() { [[ ${1} =~ ^[0-9]+$ ]]; }
isInteger() { [[ ${1} == ?(-)+([0-9]) ]]; }
isFloat() { [[ ${1} == ?(-)@(+([0-9]).*([0-9])|*([0-9]).+([0-9]))?(E?(-|+)+([0-9])) ]]; }
isNumber() { isNaturalNumber $1 || isInteger $1 || isFloat $1; }


这可以通过使用grep查看所讨论的变量是否与扩展正则表达式匹配来实现。

测试整数1120

1
2
3
4
5
6
yournumber=1120
if [ $(echo"$yournumber" | grep -qE '^[0-9]+$'; echo $?) -ne"0" ]; then
    echo"Error: not a number."
else
    echo"Valid number."
fi

输出:Valid number.

测试非整数1120a

1
2
3
4
5
6
yournumber=1120a
if [ $(echo"$yournumber" | grep -qE '^[0-9]+$'; echo $?) -ne"0" ]; then
    echo"Error: not a number."
else
    echo"Valid number."
fi

输出:Error: not a number.

解释

  • grep-E开关允许我们使用扩展正则表达式'^[0-9]+$'。这个正则表达式意味着变量应该只有[]包含从^开始到变量$结束的数字0-90到9,并且至少有+一个字符。
  • grep-q静音开关关闭任何输出,无论是否发现任何东西。
  • $?是上一个已执行命令的退出状态。退出状态0表示成功,任何更大的状态都表示错误。grep命令如果发现匹配,则其退出状态为0;如果不匹配,则其退出状态为1
  • $()是一个子shell,它允许我们执行另一个命令,然后使用输出。

综合起来,在$()子壳中,我们用echo把变量$yournumber|输送到grep上,-q开关无声地匹配-E扩展正则表达式'^[0-9]+$'表达式。然后我们把echo作为$?的退出状态,如果grep成功地找到了一个匹配,那么这个状态就是0,如果没有,这个状态就是1

现在,在$()子层之外,回到if条件下,我们从$()子层获取输出,或者是01,并检查它是否是-ne不等于"0"。如果不匹配,则退出状态为1,与"0"不匹配。那么,我们就开始了。如果匹配成功,则退出状态输出为0,等于"0",在这种情况下,则为echo"Valid number."

对于浮球或双打

对于float或double,我们只需将正则表达式从'^[0-9]+$'更改为'^[0-9]*+\.?[0-8]+$'

试验浮球1120.01

1
2
3
4
5
6
yournumber=1120.01
if [ $(echo"$yournumber" | grep -qE '^[0-9]*+\.?[0-8]+$'; echo $?) -ne"0" ]; then
    echo"Error: not a number."
else
    echo"Valid number."
fi

输出:Valid number.

试验浮球11.20.01

1
2
3
4
5
6
yournumber=11.20.01
if [ $(echo"$yournumber" | grep -qE '^[0-9]*+\.?[0-8]+$'; echo $?) -ne"0" ]; then
    echo"Error: not a number."
else
    echo"Valid number."
fi

输出:Error: not a number.

否定词

要允许负整数,只需将正则表达式从'^[0-9]+$'更改为'^\-?[0-9]+$'

为了允许负浮点数或双精度数,只需将正则表达式从'^[0-9]*+\.?[0-8]+$'更改为'^\-?[0-9]*+\.?[0-8]+$'


我使用以下(整数):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
## ##### constants
##
## __TRUE - true (0)
## __FALSE - false (1)
##
typeset -r __TRUE=0
typeset -r __FALSE=1

## --------------------------------------
## isNumber
## check if a value is an integer
## usage: isNumber testValue
## returns: ${__TRUE} - testValue is a number else not
##
function isNumber {
  typeset TESTVAR="$(echo"$1" | sed 's/[0-9]*//g' )"
  ["${TESTVAR}"x =""x ] && return ${__TRUE} || return ${__FALSE}
}

isNumber $1
if [ $? -eq ${__TRUE} ] ; then
  print"is a number"
fi


这里用一个正则表达式来测试整个部分和小数部分,用一个点分隔。

1
2
3
4
5
6
7
8
re="^[0-9]*[.]{0,1}[0-9]*$"

if [[ $1 =~ $re ]]
then
   echo"is numeric"
else
  echo"Naahh, not numeric"
fi


我试过UltraSawBlade的配方,因为它对我来说似乎是最实用的,但无法使它发挥作用。最后,我设计了另一种方法,基于参数替换的其他方法,这次使用regex替换:

1
[["${var//*([[:digit:]])}" ]]; && echo"$var is not numeric" || echo"$var is numeric"

它删除$var中的every:digit:class字符,并检查是否留下空字符串,这意味着原始字符只是数字。

我喜欢这款车的特点是占地面积小,灵活性强。在这种形式中,它只适用于非分隔的、以10为基数的整数,尽管您肯定可以使用模式匹配来满足其他需求。


快速和肮脏:我知道这不是最优雅的方式,但我通常只是在它上面加一个零,然后测试结果。像这样:

1
2
3
4
5
6
7
8
9
function isInteger {
  [ $(($1+0)) != 0 ] && echo"$1 is a number" || echo"$1 is not a number"
 }

x=1;      isInteger $x
x="1";    isInteger $x
x="joe";  isInteger $x
x=0x16 ;  isInteger $x
x=-32674; isInteger $x

如果$1不是整数,$($1+0))将返回0或bomb。例如:

1
2
3
4
5
6
7
8
9
10
function zipIt  { # quick zip - unless the 1st parameter is a number
  ERROR="not a valid number."
  if [ $(($1+0)) != 0 ] ; then  # isInteger($1)
      echo" backing up files changed in the last $1 days."
      OUT="zipIt-$1-day.tgz"
      find . -mtime -$1 -type f -print0 | xargs -0 tar cvzf $OUT
      return 1
  fi
    showError $ERROR
}

注意:我想我从来没有想过检查浮动或混合类型,将使整个脚本炸弹…就我而言,我不想再继续下去了。我将讨论mrucci的解决方案和duffy的regex——它们在bash框架中看起来最强大……


  • 要检查的变量

    number=12345number=-23234number=23.167number=-345.234

  • 检查数字或非数字

    echo $number | grep -E '^-?[0-9]*\.?[0-9]*$' > /dev/null

  • 根据上述退出状态决定进一步的行动

    if [ $? -eq 0 ]; then echo"Numeric"; else echo"Non-Numeric"; fi


我将printf用作上述的其他答案,如果您提供格式字符串"%f"或"%i",printf将为您进行检查。比重新检查更容易,语法简单简短,printf无处不在。所以在我看来,这是一个不错的选择——你也可以用下面的想法来检查一系列的事情,它不仅对检查数字有用。

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
35
declare  -r CHECK_FLOAT="%f"  
declare  -r CHECK_INTEGER="%i"  

 ##  Number - Number to check  
 ##  String - Number type to check  
 ##  String - Error message  
function check_number() {
  local NUMBER="${1}"
  local NUMBER_TYPE="${2}"
  local ERROR_MESG="${3}"
  local -i PASS=1
  local -i FAIL=0  
  case"${NUMBER_TYPE}" in
   "${CHECK_FLOAT}")
        if ((! $(printf"${CHECK_FLOAT}""${NUMBER}" &>/dev/random;echo $?))); then
           echo"${PASS}"
        else
           echo"${ERROR_MESG}" 1>&2
           echo"${FAIL}"
        fi
        ;;                
   "${CHECK_INTEGER}")
        if ((! $(printf"${CHECK_INTEGER}""${NUMBER}" &>/dev/random;echo $?))); then
           echo"${PASS}"
        else
           echo"${ERROR_MESG}" 1>&2
           echo"${FAIL}"
        fi
        ;;                
                     *)
        echo"Invalid number type format: ${NUMBER_TYPE} to check_number()." 1>&2
        echo"${FAIL}"
        ;;                
   esac
}

>$ var=45

>$ (($(check_number $var"${CHECK_INTEGER}""Error: Found $var - An integer is required."))) && { echo"$var+5" | bc; }


跟进10月13日大卫W的回答,如果使用expr,可能会更好。

1
2
3
4
test_var=`expr $am_i_numeric \* 0` >/dev/null 2>&1
if ["$test_var" ="" ]
then
    ......

如果是数字,乘以1得到相同的值(包括负数)。否则你会得到你可以测试的null


要捕获负数:

1
2
3
4
5
6
if [[ $1 == ?(-)+([0-9.]) ]]
    then
    echo number
else
    echo not a number
fi


1
2
printf '%b'"-123
ABC"
| tr '[:space:]' '_' | grep -q '^-\?[[:digit:]]\+$' && echo"Integer." || echo"NOT integer."

如果不接受负整数,则删除grep匹配模式中的-\?


我喜欢阿尔贝托·扎卡尼的回答。

1
if ["$var" -eq"$var" ] 2>/dev/null; then

重要前提条件:-没有生成子层-未调用重新分析程序-大多数shell应用程序不使用实数

但是,如果$var是复杂的(例如关联数组访问),并且数字将是非负整数(大多数用例),那么这可能更有效?

1
if ["$var" -ge 0 ] 2> /dev/null; then ..

对于我的问题,我只需要确保用户不会意外地输入某些文本,因此我试图保持它的简单和可读性。

1
2
3
isNumber() {
    (( $1 )) 2>/dev/null
}

根据手册,这是我想要的

If the value of the expression is non-zero, the return status is 0

为了防止"可能是数字"的字符串出现错误消息,我忽略了错误输出

1
2
$ (( 2s ))
bash: ((: 2s: value too great for base (error token is"2s")

您也可以这样使用"let":

1
2
3
4
5
6
7
8
9
10
[ ~]$ var=1
[ ~]$ let $var && echo"It's a number" || echo"It's not a number"
It\'s a number
[ ~]$ var=01
[ ~]$ let $var && echo"It's a number" || echo"It's not a number"
It\'s a number
[ ~]$ var=toto
[ ~]$ let $var && echo"It's a number" || echo"It's not a number"
It\'s not a number
[ ~]$

但是我更喜欢使用"=~"bash 3+操作符,就像这个线程中的一些答案一样。


我发现了一个很短的版本:

1
2
3
4
5
function isnum()
{
    return `echo"$1" | awk -F"
"
'{print ($0 != $0+0)}'`
}


如果安装了Perl,那么这一行程序简单、可读且可扩展。

1
perl -se 'exit($n !~ /\d+/)' -- -n=a

这是一些测试

1
2
3
4
perl -se 'exit($n !~ /\d+/)' -- -n=a; echo $?
1
perl -se 'exit($n !~ /\d+/)' -- -n=2; echo $?
0

这是很自我解释的,但这里有更多的信息

  • -E支持评估
  • -s允许在…在这种情况下,-n之后传递参数。
  • !~是否定的regexp匹配运算符,因为bash中的0是成功的,所以如果-n参数是一个数字,我们希望它成功退出。

您将希望用一个函数包装它,这里有一个更好的版本,可以读取浮动。

1
is_number() { perl -se 'exit($n !~ /^\d+(\.\d+)?$/)' -- -n="$1"; }

接受的答案在这里不起作用,我在用MacOS。以下代码有效:

1
2
3
4
5
if [ $(echo"$number" | grep -c '^[0-9]\+$') = 0 ]; then
    echo"it is a number"
else
    echo"not a number"
fi


Stack弹出一条消息,问我30+个答案后是否真的想回答?当然可以!!!!使用bash的新特性,这里是:(在评论之后,我做了一个更改)

function isInt() { ([[ $1 -eq $(( $1 + 0 )) ]] 2>/dev/null &&
[[ $1 != '' ]] && echo 1) || echo '' }

1
2
3
function isInt() {
   ([[ $1 =~ ^[-+0-9]+$  ]] && [[ $1 -eq $(( $1 + 0 )) ]] 2>/dev/null && [[ $1 != '' ]] && echo 1) || echo ''
}

支持:

1
2
3
4
5
6
7
8
9
10
11
12
13
===============out-of-the-box==================
 1. negative integers (true & arithmetic),
 2. positive integers (true & arithmetic),
 3. with quotation (true & arithmetic),
 4. without quotation (true & arithmetic),
 5. all of the above with mixed signs(!!!) (true & arithmetic),
 6. empty string (false & arithmetic),
 7. no value (false & arithmetic),
 8. alphanumeric (false & no arithmetic),
 9. mixed only signs (false & no arithmetic),
================problematic====================
 10. positive/negative floats with 1 decimal (true & NO arithmetic),
 11. positive/negative floats with 2 or more decimals (FALSE & NO arithmetic).

只有当结合使用过程替换(如[[ $( isInt ) ]]中的过程替换)时,才能从函数中获得true/false,因为bash中没有逻辑类型,也没有函数的返回值。

当测试表达式的结果错误时,我使用大写,但是,它应该是相反的!

"算术"的意思是bash可以像这个表达式中那样做数学:$x=$(( $y + 34))

我在数学表达式中使用"算术/非算术"时,参数的行为如预期,与预期相比,参数的行为不当时,使用"非算术"。

如你所见,只有10号和11号是有问题的!

很完美!

附言:注意,最流行的答案在案例9中失败了!


这有点粗糙的边缘,但有点新手友好。

1
2
3
4
5
6
if [ $number -ge 0 ]
then
echo"Continue with code block"
else
echo"We matched 0 or $number is not a number"
fi

这将导致错误并打印"非法数字:",如果$number不是数字,但它不会从脚本中中断。奇怪的是,我找不到一个只测试整数的测试选项。这里的逻辑将匹配任何大于或等于0的数字。


下面是我编写的一个脚本,用于与Nagios的脚本集成,目前它工作正常

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
# Script to test variable is numeric or not
# Shirish Shukla
# Pass arg1 as number
a1=$1
a=$(echo $a1|awk '{if($1 > 0) print $1; else print $1"*-1"}')
b=$(echo"scale=2;$a/$a + 1" | bc -l 2>/dev/null)
if [[ $b > 1 ]]
then
    echo"$1 is Numeric"
else
    echo"$1 is Non Numeric"
fi

如:

1
2
3
4
5
6
7
8
# sh isnumsks.sh  "-22.22"
-22.22 is Numeric

# sh isnumsks.sh  "22.22"
22.22 is Numeric

# sh isnumsks.sh  "shirish22.22"
shirish22.22 is Non  Numeric