在Bash中如何测试一个变量是否为数字?

866

我无法弄清楚如何确保传递给我的脚本的参数是数字还是其他类型。

我想要做的只是像这样:

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

需要帮助吗?


21
顺便提一下 - 你正在使用的 test && echo "foo" && exit 0 || echo "bar" && exit 1 方法可能会产生一些意想不到的副作用 - 如果 Echo 失败了(也许输出到了一个关闭的FD),exit 0 将被跳过,然后代码将尝试 echo "bar"。如果这也失败了,&& 条件将失败,甚至不会执行 exit 1! 使用实际的 if 语句而不是 &&/|| 更不容易出现意外的副作用。 - Charles Duffy
12
有点晚参加派对了,但我知道Charles所写的危险性,因为我之前也经历过。这里是一个100%无懈可击(而且易于阅读)的命令行:[[ $1 =~ "^[0-9]+$" ]] && { echo "number"; exit 0; } || { echo "not a number"; exit 1; } 大括号表示不应该在子shell中执行事情(如果使用圆括号 () 就会明确这种情况)。注意:永远不要漏掉最后的分号。否则,你可能会导致bash打印出最丑陋(并且毫无意义)的错误消息... - syntaxerror
8
除非您不删除引号,否则它在Ubuntu中无法正常工作。因此,应该只是 [[ 12345 =~ ^ [0-9] + $]] && echo OKKK || echo NOOO - Treviño
7
请提供更具体的信息,说明您所说的“number”是指什么。指整数?定点数?科学(“e”)表示法?是否需要在特定范围内(例如64位无符号值),或者允许任何可写成数字形式的数字? - Toby Speight
2
Bash确实提供了一种可靠的方法来确定一个数字是否为整数。{ VAR="asdfas" ; (( VAR )) ; echo $?; } 如果答案是'0',则该方程将正确失败,因为'0'不是整数。我几分钟前也遇到了同样的问题,并通过快速搜索找到了这个线程。我希望这能帮助其他人。其他人也接近了。 - That one guy from the movie
显示剩余5条评论
41个回答

1121

一种方法是使用正则表达式,像这样:

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

如果该值不一定是整数,请相应地修改正则表达式;例如:

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

...或者,处理带有符号的数字:

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

10
支持这种方法,但小数点需要注意,例如使用“1.0”或“1,0”进行测试会打印“错误:不是数字”。我会为您翻译成中文: 赞同这种方法,但是要注意小数点。例如,使用“1.0”或“1,0”进行测试会打印“错误:不是数字”。 - sourcerebels
5
@Ben,你真的想要处理多个减号吗?我建议将它写成“^-?”而不是“^-*”,除非你确实需要正确地处理多个倒置。 - Charles Duffy
55
我不确定为什么正则表达式需要保存在一个变量中,但如果是为了兼容性,我认为这并不必要。你可以直接应用这个表达式:[[ $yournumber =~ ^[0-9]+$ ]] - konsolebox
8
@konsolebox 是的,兼容性。在=~右侧的字面正则表达式中反斜杠处理在3.1和3.2之间有所改变,而在赋值中反斜杠处理在所有相关版本的bash中都是不变的。因此,始终将正则表达式分配给变量,然后使用=~进行匹配可以避免意外。即使这个特定的正则表达式没有反斜杠转义,我也会这样做来教导好的习惯。 - Charles Duffy
5
我做了这个命令:if [[ 123 =~ '^[0-9]+$' ]]; then echo good; fi,但没有输出结果。但是这个命令:re='^[0-9]+$'; if [[ 123 =~ $re ]]; then echo good; fi 输出了 good。为什么?我需要在第一个版本中转义一些内容吗? - Frozen Flame
显示剩余33条评论

398

不使用 bashisms(即使在 System V sh 中也可以工作),

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

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

对于负数或浮点数需要一些额外的处理。一个想法是在第一个“不好”的模式中排除-/.并添加更多的“不好”的模式,其中包含它们的不适当使用(?*-*/*.*.*)。


27
+1是一种惯用语,可以在原始的Bourne shell中使用,并具有内置对通配符的支持。如果你来自另一种编程语言,它看起来可能很奇怪,但它比应对各种引号问题和无休止的向后/侧向兼容性问题的if test...更加优雅。 - tripleee
6
你可以将第一行更改为${string#-}(这在旧版Bourne shell中不起作用,但在任何POSIX shell中都起作用),以接受负整数。 - Gilles 'SO- stop being evil'
4
此外,对于浮点数的扩展也很简单--只需将'.'|*.*.*添加到不允许的模式中,并将点号添加到允许的字符中。同样地,您可以在前面允许一个可选的符号,尽管这时我更喜欢使用case ${string#[-+]}来忽略符号。 - tripleee
3
由于case命令不会对该单词执行单词拆分和路径名生成,因此不需要使用引号。 (但是,在case模式中的扩展可能需要引用,因为它确定模式匹配字符是字面还是特殊字符。) - jilles
2
管道符号(竖杠)的解释: https://unix.stackexchange.com/questions/85939/what-is-the-pipe-character-xy-in-the-case-statement - Roland
显示剩余3条评论

263

以下解决方案也适用于基本的Shell,例如Bourne,无需使用正则表达式。 基本上,任何使用非数字进行数值评估操作都将导致错误,这将被隐式地视为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在没有数字时打印出的“需要整数表达式”的信息。

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

  • 带有小数点的数字不被视为有效的“数字”
  • 使用[[ ]]而不是[ ]将始终评估为true
  • 大多数非Bash shell将始终将此表达式评估为true
  • Bash中的行为未经记录,因此可能会在不提前警告的情况下更改
  • 如果值包含数字后的空格(例如,“1 a”),则会产生错误,如bash:[[: 1 a:表达式中的语法错误(错误令牌为“a”)
  • 如果值与变量名相同(例如i =“i”),则会产生错误,如bash:[[: i:超过表达式递归级别(错误令牌为“i”)

11
我仍然建议这样做(但要引用变量以允许为空的字符串),因为结果保证在Bash中可以作为数字使用,无论如何。 - l0b0
23
请注意使用单括号;[[ a -eq a ]]将被评估为 true(两个参数都被转换为零)。 - Tgr
3
非常好!请注意,这只适用于整数,而不是任何数字。我需要检查单个参数是否为整数,所以这很有效:if ! [ $# -eq 1 -o "$1" -eq "$1" ] 2>/dev/null; then - haridsv
6
我强烈建议不要使用这种方法,因为有相当数量的shell会将[内置函数中的参数作为算术表达式进行求值,包括ksh93和mksh。此外,由于这两个shell都支持数组,存在易受代码注入攻击的风险。请改用模式匹配。 - ormaaj
3
在当前版本的bash中,这些值仅在[[ ]]中按数字环境规则解释,而不适用于[ ]。也就是说,这种行为未被POSIX标准或bash自己的文档所指定;未来的bash版本可能会修改行为以匹配ksh,而不会违反任何记录的行为承诺,因此依赖其当前的行为并不保证是安全的。 - Charles Duffy
显示剩余11条评论

80

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

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

或者使用POSIX字符类

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

6
Glenn,我从你的帖子中删除了 shopt -s extglob(我点赞了它,这是我在这里最喜欢的答案之一),因为在条件结构中,你可以读到:当使用 ==!= 运算符时,运算符右侧的字符串被视为模式,并根据下面在模式匹配中描述的规则进行匹配,就好像启用了 extglob shell 选项。 希望你不介意! - gniourf_gniourf
3
@Jdamian:你是对的,这个功能在Bash 4.1中添加(该版本于2009年底发布)……Bash 3.2于2006年发布,现在已经是一款古老的软件了,对那些被困在过去的人感到抱歉。此外,你可以认为扩展模式extglobs是在版本2.02(于1998年发布)中引入的,在低于2.02版本中不起作用……现在你在这里的评论将作为对旧版本的警告。 - gniourf_gniourf
1
[[...]] 中的变量不受单词拆分或通配符扩展的影响。 - glenn jackman
1
@ThiagoConrado,请在手册中查找[[...]](或在bash提示符下键入help [[):只有==右侧是一个模式。 - glenn jackman
1
使用[[:digit:]]代替[:digit:]来匹配POSIX。 - bugi
显示剩余14条评论

64

一些性能和兼容性提示

不同类型的测试有一些强烈不同的方法。

我回顾了大多数相关的方法并建立了这个比较。

无符号整数 is_uint()

这些函数实现了用于评估一个表达式是否为无符号整数(即完全由数字组成)的代码。

  • Using parameter expansion

    (This was my approach before all this!)

    isuint_Parm() { [ "$1" ] && [ -z "${1//[0-9]}" ] ;}
    
  • Using fork to grep

    isuint_Grep() { grep -qE '^[0-9]+$' <<<"$1"; }
    

    I test this method only once because it's very slow. This is just there to show what not to do.

  • Using integer capabilities

    isuint_Bash() { (( 10#$1 >= 0 )) 2>/dev/null ;}
    

    or better:

    isuint_Bash() { set -- ${1//[+-]/.};(( 10#$1 >= 0 )) 2>/dev/null ;}
    
  • Using case

    isuint_Case() { case $1 in ''|*[!0-9]*) return 1;;esac;}
    
  • Using 's regex

    isuint_Regx() { [[ $1 =~ ^[0-9]+$ ]] ;}
    

有符号整数is_int()

这些函数实现了代码来判断一个表达式是否为有符号整数,即允许数字前有可选的符号。

  • Using parameter expansion

    isint_Parm() { local chk=${1#[+-]}; [ "$chk" ] && [ -z "${chk//[0-9]}" ] ;}
    
  • Using integer capabilities

    isint_Bash() {  set -- "${1//[!+-]}" ${1#${1//[!+-]}};
                    (( ( 0 ${1:-+} 10#$2 ) ? 1:1 )) 2>/dev/null ;}
    
  • Using case

    isint_Case() { case ${1#[-+]} in ''|*[!0-9]*) return 1;;esac;}
    
  • Using 's regex

    isint_Regx() { [[ $1 =~ ^[+-]?[0-9]+$ ]] ;}
    

数字(无符号浮点数)is_num()

这些函数实现了用于判断表达式是否为浮点数的代码,即允许可选的小数点和小数点后的其他数字。但是,它不尝试覆盖科学计数法表示的数字表达式(例如1.0234E-12)。

  • Using parameter expansion

    isnum_Parm() { local ck=${1#[+-]};ck=${ck/.};[ "$ck" ]&&[ -z "${ck//[0-9]}" ];}
    
  • Using 's regex

    isnum_Regx() { [[ $1 =~ ^[+-]?([0-9]+([.][0-9]*)?|\.[0-9]+)$ ]] ;}
    
  • Using case

    isnum_Case() { case ${1#[-+]} in ''|.|*[!0-9.]*|*.*.*) return 1;; esac ;}
    

概念测试

(您可以在先前声明的函数后复制/粘贴此测试代码。)

testcases=(
    0  1 42 -3 +42 +3. .9 3.14 +3.141 -31.4 '' . 3-3 3.1.4 3a a3 blah 'Good day!'
);printf '%-12s %4s %4s %4s %4s %4s %4s %4s %4s %4s %4s %4s %4s\n' Value\\Func \
    U{Prm,Grp,Bsh,Cse,Rgx} I{Prm,Bsh,Cse,Rgx} N{Prm,Cse,Rgx};\
for var in "${testcases[@]}";do
    outstr='';
    for func in isuint_{Parm,Grep,Bash,Case,Regx} isint_{Parm,Bash,Case,Regx} \
                isnum_{Parm,Case,Regx};do
        if $func "$var"; then
            outstr+='   ##'
        else
            outstr+='   --'
        fi
    done
    printf '%-11s %s\n' "$var" "$outstr"
done

应输出:
Value\Func   UPrm UGrp UBsh UCse URgx IPrm IBsh ICse IRgx NPrm NCse NRgx
0              ##   ##   ##   ##   ##   ##   ##   ##   ##   ##   ##   ##
1              ##   ##   ##   ##   ##   ##   ##   ##   ##   ##   ##   ##
42             ##   ##   ##   ##   ##   ##   ##   ##   ##   ##   ##   ##
-3             --   --   --   --   --   ##   ##   ##   ##   ##   ##   ##
+42            --   --   --   --   --   ##   ##   ##   ##   ##   ##   ##
+3.            --   --   --   --   --   --   --   --   --   ##   ##   ##
.9             --   --   --   --   --   --   --   --   --   ##   ##   ##
3.14           --   --   --   --   --   --   --   --   --   ##   ##   ##
+3.141         --   --   --   --   --   --   --   --   --   ##   ##   ##
-31.4          --   --   --   --   --   --   --   --   --   ##   ##   ##
               --   --   --   --   --   --   --   --   --   --   --   --
.              --   --   --   --   --   --   --   --   --   --   --   --
3-3            --   --   --   --   --   --   ##   --   --   --   --   --
3.1.4          --   --   --   --   --   --   --   --   --   --   --   --
3a             --   --   --   --   --   --   --   --   --   --   --   --
a3             --   --   --   --   --   --   --   --   --   --   --   --
blah           --   --   --   --   --   --   --   --   --   --   --   --
Good day!      --   --   --   --   --   --   --   --   --   --   --   --

我希望!(注意:uint_bash 似乎并不完美!)

性能比较

然后我建立了这个测试函数:

testFunc() {
    local tests=1000 start=${EPOCHREALTIME//.}
    for ((;tests--;)) ;do
        "$1" "$3"
    done
    printf -v "$2" %u $((${EPOCHREALTIME//.}-start))
}
percent(){ local p=00$((${1}00000/$2));printf -v "$3" %.2f%% ${p::-3}.${p: -3};}
sortedTests() {
    local func NaNTime NumTime ftyp="$1" nTest="$2" tTest="$3" min i pct line
    local -a order=()
    shift 3
    for func ;do
        testFunc "${ftyp}_$func" NaNTime "$tTest"
        testFunc "${ftyp}_$func" NumTime "$nTest"
        order[NaNTime+NumTime]=${ftyp}_$func\ $NumTime\ $NaNTime
    done
    printf '%-12s %11s %11s %14s\n' Function Number NaN Total
    min="${!order[*]}" min=${min%% *}
    for i in "${!order[@]}";do
        read -ra line <<<"${order[i]}"
        percent "$i" "$min" pct
        printf '%-12s %9d\U00B5s %9d\U00B5s  %12d\U00B5s  %9s\n' \
               "${line[@]}" "$i" "$pct"
    done
}

我可以用这种方式运行:

sortedTests isuint "This is not a number." 31415926535897932384 \
            Case Grep Parm Bash Regx ;\
sortedTests isint  "This is not a number." 31415926535897932384 \
            Case Parm Bash Regx ;\
sortedTests isnum "This string is clearly not a number..." \
            3.141592653589793238462643383279502884  Case Parm Regx

在我的主机上,它显示类似于:
Function          Number         NaN          Total
isuint_Case       6499µs      6566µs         13065µs    100.00%
isuint_Parm      26687µs     31600µs         58287µs    446.13%
isuint_Regx      36511µs     40181µs         76692µs    587.00%
isuint_Bash      43819µs     40311µs         84130µs    643.93%
isuint_Grep    1298265µs   1224112µs       2522377µs  19306.37%

Function          Number         NaN          Total
isint_Case       22687µs     21914µs         44601µs    100.00%
isint_Parm       35765µs     34428µs         70193µs    157.38%
isint_Regx       36949µs     42319µs         79268µs    177.73%
isint_Bash       55368µs     65095µs        120463µs    270.09%

Function          Number         NaN          Total
isnum_Case       23313µs     23446µs         46759µs    100.00%
isnum_Parm       35677µs     42169µs         77846µs    166.48%
isnum_Regx       51864µs     69502µs        121366µs    259.56%

你可以下载完整的数字比较脚本以文本形式呈现的完整数字比较脚本(包含UTF8和LATIN处理)。

结论

  • case 方法显然是最快的!大约比regex快3倍,比使用参数扩展快2倍。
  • 尽量避免不必要的分叉(到grep或任何二进制文件)。

case方法已成为我首选的选择:

is_uint() { case $1        in '' | *[!0-9]*              ) return 1;; esac ;}
is_int()  { case ${1#[-+]} in '' | *[!0-9]*              ) return 1;; esac ;}
is_unum() { case $1        in '' | . | *[!0-9.]* | *.*.* ) return 1;; esac ;}
is_num()  { case ${1#[-+]} in '' | . | *[!0-9.]* | *.*.* ) return 1;; esac ;}

关于兼容性:
为此,我编写了一个基于先前测试的小型测试脚本,其中包括:
for shell in bash dash 'busybox sh' ksh zsh "$@";do
    printf "%-12s  " "${shell%% *}"
    $shell < <(testScript) 2>&1 | xargs
done

这显示:
bash          Success
dash          Success
busybox       Success
ksh           Success
zsh           Success

据我所知,其他基于的解决方案,如正则表达式的整数在许多其他shell中都无法工作,而forks会消耗资源,因此我更喜欢case方法(就在参数扩展之前,这种方法也大多数兼容)。

@CharlesDuffy,在我的树莓派上,使用我的版本进行1000次迭代只需要2.5秒,而使用你的版本则需要4.4秒! - F. Hauri - Give Up GitHub
已经在处理中:isnum(){ case ${1#[-+]} in ''|*[!0-9.]*|*.*.*) return -1;;esac ;}...看起来不错! - F. Hauri - Give Up GitHub
也许你会注意到,在NaN测试中,isuint_Bashcase稍微快一些。如果你处于一个每个周期都很重要的紧密循环中,并且你预计大部分输入都是无效的,那么这可能会使参数扩展版本更有优势。但仅适用于uint情况。也许差异很小,已经在测量误差范围内了。 - tripleee
1
@tripleee 请按照发布的方式重新测试,多次在我的桌子相对安静的时候进行测试,然后选择更相关的输出结果发布。 (你试过我的脚本吗?我添加了一个“+数字”列,我不会在这里解释;) - F. Hauri - Give Up GitHub
1
根据这些解决方案,你可以扩展到包括科学计数法的完整浮点数比较:is_float() { is_num "${1/[eE][-+]/}"; } - kvantour
显示剩余9条评论

57

这个脚本测试一个数字是否为非负整数。它与 shell 无关(即没有 bashism)并且只使用了 shell 内建指令:

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

这个答案的早期版本提出了以下建议:

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

但这是不正确的,因为它接受任何以数字开头的字符串,正如jilles建议的


6
这个功能无法正常工作,它会接受以数字开头的任何字符串。请注意,在${VAR##WORD}和类似情况下,WORD是shell模式而不是正则表达式。 - jilles
3
请问你能把那个表达翻译成英文吗?我真的很想用它,但是即使我仔细阅读了bash手册,我还是不太理解它,无法信任它。 - CivFan
4
*[!0-9]* 是一个匹配至少有1个非数字字符的所有字符串的模式。 ${num##*[!0-9]*} 是“参数扩展”,它获取 num 变量的内容并删除与该模式匹配的最长字符串。 如果参数扩展的结果不为空 (! [ -z ${...} ]),则它是一个数字,因为它不包含任何非数字字符。 - mrucci
不幸的是,即使参数中有任何数字,甚至不是有效数字,此方法都会失败。例如,“exam1ple”或“a2b”。 - studgeek
两者都失败了,显示 122s :-( - Hastur
1
但这很好,因为“exam1ple”、“a2b”和“122s”都不是数字。 - nooblag

27

我对在shell中直接解析数字格式的解决方案感到惊讶。由于shell是用于控制文件和进程的DSL,因此不太适合这样做。在稍低层次上有足够的数字解析器可供使用,例如:

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”更改为您需要的特定格式。


4
isnumber()函数用于判断传入的参数是否为数字,如果是数字则输出“this is a number”,否则输出“not a number”。函数实现中,使用printf命令格式化第一个参数为%f,然后将标准输出和标准错误输出都重定向到/dev/null,以避免输出结果干扰函数返回值的判断。如果printf命令执行成功,则说明第一个参数是数字,函数返回0;否则,第一个参数不是数字,函数返回1。最后,使用逻辑与(&&)和逻辑或(||)运算符对printf命令的执行结果进行判断,并输出相应信息。 - Gilles Quénot
4
@sputnick,你的版本破坏了原函数固有(且有用的)的返回值语义。因此,最好保持函数不变,并使用它:isnumber 23 && echo "this is a number" || echo "not a number"。请注意,这是一句建议,而非解释。 - michael
4
这句话的意思是:难道这里也不应该加上 2>/dev/null 吗?这样一来,isnumber "foo" 就不会污染标准错误输出了。 - gioele
4
将像bash这样的现代shell称为“用于控制文件和进程的DSL”是忽略了它们被用于更多的目的 - 一些发行版甚至使用其构建了整个软件包管理器和Web界面(尽管可能不太美观)。批处理文件符合您的描述,因为即使在其中设置变量也很困难。 - Camilo Martin
7
你试图聪明地从其他语言中复制一些成语,这很有趣。不幸的是,在shell中这是行不通的。Shell非常特殊,如果没有扎实的知识,你很可能会写出错误的代码。你的代码有问题:isnumber "'a"将返回true。在POSIX规范中有记录,你可以看到:如果前导字符是单引号或双引号,则该值应为后面紧随单引号或双引号的字符在底层代码集中的数字值。 - gniourf_gniourf
显示剩余12条评论

22

我在看回答时发现没人提到带点的浮点数!

使用grep也很好。 -E表示扩展正则表达式。 -q表示安静模式(不回显)。 -qE是两者的组合。

在命令行中直接测试:

$ 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脚本中使用:

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

要仅匹配整数,请使用以下内容:

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

triple_r和tripleee使用awk编写的解决方案适用于浮点数。 - Ken Jackson
谢谢您的回复,非常好的观点!因为问题实际上是如何检查它是否为数值而不仅仅是整数。 - Tanasis
我也感谢你,Tanasis!让我们永远互相帮助。 - Sergio Abreu

14

这只是对@mary的跟进,但由于我的声望不够,无法将此评论发布到该帖子中。无论如何,这就是我所使用的:

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

如果参数是一个数字,该函数将返回"1",否则将返回"0"。这适用于整数和浮点数。使用方法大致如下:

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

5
打印一个数字比设置退出代码不太有用。'BEGIN { exit(1-(a==a+0)) }' 稍微有点难以理解,但可以在返回 true 或 false 的函数中使用,就像 [, grep -q 等一样。 - tripleee

11

对于我的问题,我只需要确保用户不会意外输入文本,因此我尝试保持简单和易读

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

根据手册上的说明,这基本上就是我想要的。

如果表达式的值为非零,则返回状态为0。

为了防止针对“可能是数字”的字符串出现不良错误消息,我忽略错误输出。

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

2
这是错误的(有漏洞)!请尝试这样做:foo=1;set -- foo;(( $1 )) 2>/dev/null && echo "'$1' 是一个数字" - F. Hauri - Give Up GitHub

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接