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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/806906/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-03 17:15:14  来源:igfitidea点击:

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

linuxbashshell

提问by Flávio Amieiro

I just can't figure out how do I make sure an argument passed to my script is a number or not.

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

All I want to do is something like this:

我想要做的就是这样:

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

Any help?

有什么帮助吗?

采纳答案by Charles Duffy

One approach is to use a regular expression, like so:

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

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

If the value is not necessarily an integer, consider amending the regex appropriately; for instance:

如果该值不一定是整数,请考虑适当修改正则表达式;例如:

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

...or, to handle numbers with a sign:

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

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

回答by Charles Duffy

This is a little rough around the edges but a little more novice friendly.

这有点粗糙,但对新手更友好。

if [ $number -ge 0 ]
then
echo "Continue with code block"
else
echo "We matched 0 or $number is not a number"
fi

This will cause an error and print "Illegal number:" if $number is not a number but it will not break out of the script. Oddly there is not a test option I could find to just test for an integer. The logic here will match any number that is greater than or equal to 0.

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

回答by Alberto Zaccagni

The following solution can also be used in basic shells such as Bourne without the need for regular expressions. Basically any numeric value evaluation operations using non-numbers will result in an error which will be implicitly considered as false in shell:

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

"$var" -eq "$var"

as in:

如:

#!/bin/bash

var=a

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

You can can also test for $? the return code of the operation which is more explicit:

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

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

Redirection of standard error is there to hide the "integer expression expected" message that bash prints out in case we do not have a number.

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

CAVEATS(thanks to the comments below):

警告(感谢以下评论):

  • Numbers with decimal points are notidentified as valid "numbers"
  • Using [[ ]]instead of [ ]will always evaluate to true
  • Most non-Bash shells will always evaluate this expression as true
  • The behavior in Bash is undocumented and may therefore change without warning
  • If the value includes spaces after the number (e.g. "1 a") produces error, like bash: [[: 1 a: syntax error in expression (error token is "a")
  • If the value is the same as var-name (e.g. i="i"), produces error, like bash: [[: i: expression recursion level exceeded (error token is "i")
  • 带小数点的数字被识别为有效的“数字”
  • 使用[[ ]]而不是[ ]将始终评估为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")

回答by Marnix

I use the following (for integers):

我使用以下(对于整数):

## ##### 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 "" | sed 's/[0-9]*//g' )"
  [ "${TESTVAR}"x = ""x ] && return ${__TRUE} || return ${__FALSE}
}

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

回答by mrucci

This tests if a number is a non negative integer and is both shell independent (i.e. without bashisms) and uses only shell built-ins:

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

INCORRECT.

不正确。

As this first answer (below) allows for integers with characters in them as long as the first are not first in the variable.

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

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

CORRECT.

正确

As jillescommented and suggested in his answerthis is the correct way to do it using shell-patterns.

正如jilles他的回答中评论和建议的那样,这是使用 shell-patterns 的正确方法。

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

回答by ultrasawblade

http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_04_03.html

http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_04_03.html

You can also use bash's character classes.

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

if [[ $VAR = *[[:digit:]]* ]]; then
 echo "$VAR is numeric"
else
 echo "$VAR is not numeric"
fi

Numerics will include space, the decimal point, and "e" or "E" for floating point.

数字将包括空格、小数点和浮点数的“e”或“E”。

But, if you specify a C-style hex number, i.e. "0xffff" or "0XFFFF", [[:digit:]] returns true. A bit of a trap here, bash allows you do to something like "0xAZ00" and still count it as a digit (isn't this from some weird quirk of GCC compilers that let you use 0x notation for bases other than 16???)

但是,如果您指定 C 风格的十六进制数,即“0xffff”或“0XFFFF”,[[:digit:]] 返回真。这里有点陷阱,bash 允许你对“0xAZ00”之类的东西做一些事情,并且仍然把它算作一个数字(这不是来自 GCC 编译器的一些奇怪的怪癖,它让你对 16 以外的基数使用 0x 符号? )

You might want to test for "0x" or "0X" before testing if it's a numeric if your input is completely untrusted, unless you want to accept hex numbers. That would be accomplished by:

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

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

回答by ata

I tried ultrasawblade's recipe as it seemed the most practical to me, and couldn't make it work. In the end i devised another way though, based as others in parameter substitution, this time with regex replacement:

我尝试了 Ultrasawblade 的配方,因为它对我来说似乎是最实用的,但无法实现。最后,我设计了另一种方法,基于参数替换中的其他方法,这次使用正则表达式替换:

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

It removes every :digit: class character in $var and checks if we are left with an empty string, meaning that the original was only numbers.

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

What i like about this one is its small footprint and flexibility. In this form it only works for non-delimited, base 10 integers, though surely you can use pattern matching to suit it to other needs.

我喜欢这个的地方在于它的占地面积小和灵活性。在这种形式中,它仅适用于非分隔的、以 10 为基数的整数,但您当然可以使用模式匹配来满足其他需求。

回答by jilles

Without bashisms (works even in the System V sh),

没有 bashisms(即使在 System V sh 中也能工作),

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

This rejects empty strings and strings containing non-digits, accepting everything else.

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

Negative or floating-point numbers need some additional work. An idea is to exclude -/ .in the first "bad" pattern and add more "bad" patterns containing the inappropriate uses of them (?*-*/ *.*.*)

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

回答by WWWIZARDS

Quick & Dirty: I know it's not the most elegant way, but I usually just added a zero to it and test the result. like so:

Quick & Dirty:我知道这不是最优雅的方式,但我通常只是给它添加一个零并测试结果。像这样:

function isInteger {
  [ $((+0)) != 0 ] && echo " is a number" || echo " 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+0)) will return 0 or bomb if $1 is NOT an integer. for Example:

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

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

NOTE: I guess I never thought to check for floats or mixed types that will make the entire script bomb... in my case, I didn't want it go any further. I'm gonna play around with mrucci's solution and Duffy's regex - they seem the most robust within the bash framework...

注意:我想我从来没有想过检查会导致整个脚本炸弹的浮点数或混合类型......在我的情况下,我不希望它更进一步。我将尝试使用 mrucci 的解决方案和 Duffy 的正则表达式——它们似乎是 bash 框架中最强大的......

回答by Shirish Shukla

Below is a Script written by me and used for a script integration with Nagios and it is working properly till now

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

#!/bin/bash
# Script to test variable is numeric or not
# Shirish Shukla
# Pass arg1 as number
a1=
a=$(echo $a1|awk '{if( > 0) print ; else print "*-1"}')
b=$(echo "scale=2;$a/$a + 1" | bc -l 2>/dev/null)
if [[ $b > 1 ]]
then
    echo " is Numeric"
else
    echo " 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