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

我只想这样做:

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

有什么帮助吗?


当前回答

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

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

function isInteger() {
    [[ ${1} == ?(-)+([0-9]) ]]
}

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

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

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))更宽容。我的单元测试只测试整数或浮点值,但不测试任何无效输入。

其他回答

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

"$var" -eq "$var"

如:

#!/bin/bash

var=a

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

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

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

标准错误的重定向是为了隐藏bash打印出的“预期整数表达式”消息,以防我们没有数字。

CAVETS(感谢以下评论):

带小数点的数字不被识别为有效的“数字”使用[[]]而不是[]将始终计算为true大多数非Bash shell始终将此表达式求值为trueBash中的行为没有记录,因此可能会在没有警告的情况下发生变化如果值在数字后面包含空格(例如“1 a”),则会产生错误,如bash:[[:1 a:表达式中的语法错误(错误标记为“a”)如果该值与var名称相同(例如i=“i”),则会产生错误,如bash:[[:i:expression递归级别超出(错误标记为“i”

以下是我编写的脚本,用于与Nagios的脚本集成,到目前为止运行正常

#!/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

EG:

# 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

你也可以像这样使用“let”:

[ ~]$ 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+运算符,就像这个线程中的一些答案一样。

没有抨击(即使在System V sh中也有效),

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

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

负数或浮点数需要一些额外的工作。一个想法是排除-/。在第一个“bad”模式中,添加更多包含不正确用法的“bad“模式(?*-*/*.*.*)

我使用以下(整数):

## ##### 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