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
How do I test if a variable is a number in Bash?
提问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 totrue
- 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