Linux 如何在Bash中测试变量是否为数字?
我只是不知道如何确保传递给脚本的参数是否为数字 我想做的就是这样:Linux 如何在Bash中测试变量是否为数字?,linux,bash,shell,Linux,Bash,Shell,我只是不知道如何确保传递给脚本的参数是否为数字 我想做的就是这样: test *isnumber* $1 && VAR=$1 || echo "need a number" 有什么帮助吗?一种方法是使用正则表达式,如下所示: re='^[0-9]+$' if ! [[ $yournumber =~ $re ]] ; then echo "error: Not a number" >&2; exit 1 fi 如果值不一定是整数,考虑适当修改正则表达式;例如
test *isnumber* $1 && VAR=$1 || echo "need a number"
有什么帮助吗?一种方法是使用正则表达式,如下所示:
re='^[0-9]+$'
if ! [[ $yournumber =~ $re ]] ; then
echo "error: Not a number" >&2; exit 1
fi
如果值不一定是整数,考虑适当修改正则表达式;例如:
^[0-9]+([.][0-9]+)?$
…或者,用符号处理数字:
^[+-]?[0-9]+([.][0-9]+)?$
下面的解决方案也可以在基本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打印出来的“integer expression expected”消息,以防我们没有数字
if [[ ! -n ${input//[0-9]/} ]]; then
echo "Input Is A Number"
fi
注意事项(感谢下面的评论):
- 带小数点的数字未标识为有效的“数字”
- 使用
而不是[[]]
将始终计算为[]
true
- 大多数非Bash shell总是将此表达式计算为
true
- Bash中的行为没有文档记录,因此可能会在没有警告的情况下更改
- 如果该值包含数字后面的空格(例如“1 a”)会产生错误,例如
bash:[:1 a:表达式中的语法错误(错误标记为“a”)
- 如果该值与var name相同(例如i=“i”),则会产生错误,如
bash:[:i:表达式递归级别超出(错误标记为“i”)
这将测试一个数字是否为非负整数,是否既与shell无关(即没有bashisms),又只使用shell内置: 不正确。 因为第一个答案(如下)允许包含字符的整数,只要第一个不是变量中的第一个
[ -z "${num##[0-9]*}" ] && echo "is a number" || echo "is not a number";
正确
正如在本文中所评论和建议的,这是使用shell模式进行此操作的正确方法
[ ! -z "${num##*[!0-9]*}" ] && echo "is a number" || echo "is not a number";
您还可以使用bash的角色类
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”是否为数字之前测试它,除非您希望接受十六进制数字。这将通过以下方式完成:
if [[ ${VARIABLE:1:2} = "0x" ]] || [[ ${VARIABLE:1:2} = "0X" ]]; then echo "$VAR is not numeric"; fi
我尝试了ultrasawblade的配方,因为它对我来说似乎是最实用的,但没有成功。尽管如此,最后我还是设计了另一种方法,与其他参数替换方法一样,这次是用正则表达式替换:
[[ "${var//*([[:digit:]])}" ]]; && echo "$var is not numeric" || echo "$var is numeric"
它删除$var中的every:digit:class字符,并检查是否留下一个空字符串,这意味着原始字符串只是数字
我喜欢的是它的占用空间小和灵活性。在这种形式下,它只适用于非分隔的、以10为基数的整数,当然你可以使用模式匹配来满足其他需要。没有bashisms(即使在System V sh中也能工作)
它拒绝空字符串和包含非数字的字符串,接受其他所有内容
负数或浮点数需要一些额外的工作。一个想法是将
-
/
排除在第一个“坏”模式中,并添加更多包含不正确使用它们的“坏”模式(?*-*
/*.
)快速和肮脏:我知道这不是最优雅的方式,但我通常只是在上面加一个零,然后测试结果。就像这样:
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。例如:
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的正则表达式-它们似乎是bash框架中最健壮的
[[ $1 =~ ^-?[0-9]+$ ]] && echo "number"
不要忘了
-
包含负数!我对直接解析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”更改为您需要的任何特定格式。我会尝试以下方法:
printf "%g" "$var" &> /dev/null
if [[ $? == 0 ]] ; then
echo "$var is a number."
else
echo "$var is not a number."
fi
注意:这将nan和inf识别为数字。没有人建议bash:
或使用:
要捕获负数,请执行以下操作:
if [[ $1 == ?(-)+([0-9.]) ]]
then
echo number
else
echo not a number
fi
我在看答案,然后。。。 意识到没有人想到浮点数(带点) 使用grep也很好。
-E表示扩展regexp
-q表示安静(不回音)
-量化宽松是两者的结合 要直接在命令行中进行测试,请执行以下操作:
$ 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]+$`
这是一个老问题,但我只是想继续我的解决方案。这个解决方案不需要任何奇怪的外壳技巧,也不需要依赖一些永远不存在的东西
if [ -n "$(printf '%s\n' "$var" | sed 's/[0-9]//g')" ]; then
echo 'is not numeric'
else
echo 'is numeric'
fi
基本上,它只是从输入中删除所有数字,如果留下一个非零长度的字符串,那么它就不是一个数字。我使用。如果尝试将零添加到非数值,它将返回一个非零:
if [[ ! -n ${input//[0-9]/} ]]; then
echo "Input Is A Number"
fi
如果表达式--“$number”+0>/dev/null 2>&1
然后
echo“$number是一个数字”
其他的
echo“$number不是一个数字”
fi
如果您需要非整数,则可以使用,但我不认为bc
具有完全相同的行为。将零添加到非数字会得到零,并且它也会返回零值。也许您可以将bc
和expr
组合使用。使用bc
将零添加到# change check line to:
check=`echo "$1" | grep -E ^\-?[0-9]+$`
if [ -n "$(printf '%s\n' "$var" | sed 's/[0-9]//g')" ]; then
echo 'is not numeric'
else
echo 'is numeric'
fi
[ ~]$ 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
[ ~]$
isnum() { awk -v a="$1" 'BEGIN {print (a == a + 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
test -z "${i//[0-9]}" && echo digits || echo no no no
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
string="-12,345"
if [[ "$string" =~ ^-?[0-9]+[.,]?[0-9]*$ ]]
then
echo $string is a number
else
echo $string is not a number
fi
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
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
parse_num() {
local r=`expr "$1" : '.*\([.,]\)' 2>/dev/null | tr -d '\n'`
nat='^[+-]?[0-9]+[.,]?$' \
dot="${1%[.,]*}${r}${1##*[.,]}" \
float='^[\+\-]?([.,0-9]+[Ee]?[-+]?|)[0-9]+$'
[[ "$1" == $dot ]] && [[ "$1" =~ $float ]] || [[ "$1" =~ $nat ]]
} # usage: parse_num -123.456
declare -r CHECK_FLOAT="%f"
declare -r CHECK_INTEGER="%i"
## <arg 1> Number - Number to check
## <arg 2> String - Number type to check
## <arg 3> 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
}
function isInteger() {
[[ ${1} == ?(-)+([0-9]) ]]
}
function isFloat() {
[[ ${1} == ?(-)@(+([0-9]).*([0-9])|*([0-9]).+([0-9]))?(E?(-|+)+([0-9])) ]]
}
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
}
if [[ ! -n ${input//[0-9]/} ]]; then
echo "Input Is A Number"
fi
if [ "$var" -eq "$var" ] 2>/dev/null; then
if [ "$var" -ge 0 ] 2> /dev/null; then ..
printf '%b' "-123\nABC" | tr '[:space:]' '_' | grep -q '^-\?[[:digit:]]\+$' && echo "Integer." || echo "NOT integer."
#!/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\n" $(isNumber $value) ${bools[$?]} $(printf "isNumber(%s)" $value)
done
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; }
re="^[0-9]*[.]{0,1}[0-9]*$"
if [[ $1 =~ $re ]]
then
echo "is numeric"
else
echo "Naahh, not numeric"
fi
yournumber=1120
if echo "$yournumber" | grep -qE '^[0-9]+$'; then
echo "Valid number."
else
echo "Error: not a number."
fi
yournumber=1120a
if echo "$yournumber" | grep -qE '^[0-9]+$'; then
echo "Valid number."
else
echo "Error: not a number."
fi
yournumber=1120.01
if echo "$yournumber" | grep -qE '^[0-9]*\.?[0-9]+$'; then
echo "Valid number."
else
echo "Error: not a number."
fi
yournumber=11.20.01
if echo "$yournumber" | grep -qE '^[0-9]*\.?[0-9]+$'; then
echo "Valid number."
else
echo "Error: not a number."
fi
isNumber() {
(( $1 )) 2>/dev/null
}
$ (( 2s ))
bash: ((: 2s: value too great for base (error token is "2s")
is_num() { [ "$1" ] && [ -z "${1//[0-9]}" ] ;}
is_num() {
local chk=${1#[+-]};
[ "$chk" ] && [ -z "${chk//[0-9]}" ]
}
is_num() {
local chk=${1#[+-]};
chk=${chk/.}
[ "$chk" ] && [ -z "${chk//[0-9]}" ]
}
set -- "foo bar"
is_num "$1" && VAR=$1 || echo "need a number"
need a number
set -- "+3.141592"
is_num "$1" && VAR=$1 || echo "need a number"
echo $VAR
+3.141592
cdIs_num() {
local re='^[+-]?[0-9]+([.][0-9]+)?$';
[[ $1 =~ $re ]]
}
if is_num foo;then echo It\'s a number ;else echo Not a number;fi
Not a number
if cdIs_num foo;then echo It\'s a number ;else echo Not a number;fi
Not a number
if is_num 25;then echo It\'s a number ;else echo Not a number;fi
It's a number
if cdIs_num 25;then echo It\'s a number ;else echo Not a number;fi
It's a number
if is_num 3+4;then echo It\'s a number ;else echo Not a number;fi
Not a number
if cdIs_num 3+4;then echo It\'s a number ;else echo Not a number;fi
Not a number
if is_num 3.1415;then echo It\'s a number ;else echo Not a number;fi
It's a number
if cdIs_num 3.1415;then echo It\'s a number ;else echo Not a number;fi
It's a number
time for i in {1..1000};do is_num +3.14159265;done
real 0m2.476s
user 0m1.235s
sys 0m0.000s
time for i in {1..1000};do cdIs_num +3.14159265;done
real 0m4.363s
user 0m2.168s
sys 0m0.000s