【问题标题】:Check that a variable is a number in UNIX shell [duplicate]检查变量是否是 UNIX shell 中的数字 [重复]
【发布时间】:2010-09-23 12:15:07
【问题描述】:

如何在 UNIX shell 中检查变量是数字还是包含数字?

【问题讨论】:

  • 标题询问变量是否为数字,描述询问变量是否包含数字。你要哪个?另外,当您说数字时,您的意思是整数还是应该处理小数?
  • 你认为 3.1415 是一个数字吗?

标签: unix shell


【解决方案1】:
if echo $var | egrep -q '^[0-9]+$'; then
    # $var is a number
else
    # $var is not a number
fi

【讨论】:

  • 我不知道这是否正确,这会检查它是否是整数(不是数字)。如果问题在描述中(“包含”),我会将正则表达式更改为“[0-9]”以满足问题,如果是标题中的问题(“是")。
  • 这样一个可以在 shell 中完成的简单操作,fork、pipe 和 egrep 浪费了多少次循环?希望这在一个紧密的循环中不需要......
  • @Jens:你说得对,这个答案不如不产生子进程的答案有效,尽管大多数情况下不会产生任何实际差异。我对你更好的答案投了赞成票。
  • @AdamRosenfield 谢谢,面对批评,这是一种崇高的姿态。世界需要更多这种态度。
  • 不要忘记负数。假设我们只讨论整数(整数),而不是浮点数(实数)——即与 test(1) 的数字运算符(-eq 等)一起使用的数字,我们可以在这里调整正则表达式方法包括这样的负整数:echo $var | egrep -q '^-*[[:digit:]]+$' && echo is num || echo not num(当然,仅适用于基数 10)。这甚至适用于过度否定但合法的数字,如 ----234。
【解决方案2】:

Shell变量没有类型,所以最简单的方法是使用返回类型test命令:

if [ $var -eq $var 2> /dev/null ]; then ...

(或者用正则表达式解析)

【讨论】:

  • 如果 var 为空,则为误报。也许:if [ -n "$var" -a $var -eq $var 2> /dev/null ]; then echo is num; else echo not a num; fi
  • 这也很好,这适用于基本的 bourne/korn shell(不需要 bashisms)。一个缺点:在我使用的 test(1) 中(FreeBSD 9、Fedora 20),当 var 被过度否定时(例如,--234),尽管算术运算有效(例如,echo $((--234 * 2))),但它会失败。
【解决方案3】:

没有叉子,没有管道。纯 POSIX 外壳:

case $var in
   (*[!0-9]*|'') echo not a number;;
   (*)           echo a number;;
esac

(假设 number := 一串数字)。如果您还想允许带有单个前导 -+ 的签名数字,请像这样去掉可选符号:

case ${var#[-+]} in
   (*[!0-9]*|'') echo not a number;;
   (*)           echo a number;;
esac

【讨论】:

  • 不处理负数(例如,-123、--123)。
  • @Juan:这就是为什么我明确提出这个假设的原因。
  • 很公平。我只是想我会清楚地说明所有各种解决方案。在其他一些情况下,支持负数相当容易。尝试使用这种方法(正常通配)支持负数更加困难。
  • @Juan 我添加了一个简单的修改以允许签名数字。感谢您的挑战:-)
  • 不错的补充。仍然不适用于反常但有效的--123。有趣的是,freebsd 的 /bin/sh sh -c 'var=--123; echo $(($var))') 处理了这个问题。但是 freebsd >= 10 没有。
【解决方案4】:

在启用 extglob 选项的 ksh93 或 bash 中:

if [[ $var == +([0-9]) ]]; then ...

【讨论】:

  • 要处理负数(甚至过度但合理地否定,如 ---234),将其调整为 if [[ $var == +(-*[[:digit:]]) ]]; then echo is num; else echo not num; fi。很好,这可以处理空的或未设置的 var 以及多字 var(例如,“棕牛”)。使用[:xdigit:] 字符类作为基数为 16 的数字。注意:与语言环境无关的字符类(例如 [:digit:])似乎不适用于 ksh。
  • 这很快就会变得复杂。尝试使用“brown cow”、“123Q”、“0xAbc”、“123 Q”、“-123”、“--345”进行测试。 bash/ksh 中“扩展正则表达式”的各种实现导致了复杂性。因基本 posix shell 缺乏可移植性而投反对票(更多的是对该方法的投反对票,而不是 Darron 的回答,因为他非常了解该限制)。
  • 你们能帮我理解一下吗:# x=200 # [[ +([0-9]) == $x ]] && echo number || echo not number > not a number # [[ $x == +([0-9]) ]] && echo number ||回显不是数字>数字
【解决方案5】:

这是一个仅使用基本外壳中可用功能的版本(即它可以在sh 中工作),并且比使用grep 少一个进程:

if expr "$var" : '[0-9][0-9]*$'>/dev/null; then
    echo yes
else
    echo no
fi

这会检查$var 是否代表一个整数;调整正则表达式以适应口味,并注意 expr 正则表达式参数隐式锚定在开头。

【讨论】:

  • 不支持取反的整数(-123、--123)。
  • 对于负数:expr "$var" : '-*[0-9][0-9]*$' && echo num || echo not num
  • 支持可移植性(例如,没有 bashisms);额外的叉子有轻微的缺点。
【解决方案6】:

这可以使用正则表达式进行检查。

 ###    
    echo $var|egrep '^[0-9]+$'
    if [ $? -eq 0 ]; then
        echo "$var is a number"
    else
        echo "$var is not a number"
    fi

【讨论】:

  • 为什么要添加这个?这个确切的方法是在亚当 2008 年的回复中。(-1)
【解决方案7】:

我是 shell 编程的新手,所以我尝试找出最简单易读的方法 它只会检查 var 是否大于或等于 0 我认为这是选择参数的好方法......可能不是以前的......:

if [ $var -ge 0 2>/dev/null ] ; then ...

【讨论】:

  • 如果 [ $var -ge 0 -o $var -lt 0 ]; then ... # 处理负数
【解决方案8】:

整数

if echo "$var" | egrep -q '^\-?[0-9]+$'; then 
    echo "$var is an integer"
else 
    echo "$var is not an integer"
fi

测试(var=2 等):

2 is an integer
-2 is an integer
2.5 is not an integer 
2b is not an integer

号码

if echo "$var" | egrep -q '^\-?[0-9]*\.?[0-9]+$'; then 
    echo "$var is a number"
else 
    echo "$var is not a number"
fi

测试(var=2 等):

2 is a number
-2 is a number
-2.6 is a number
-2.c6 is not a number
2. is not a number
2.0 is a number

【讨论】:

  • 当然,.6 是一个数字。该命令还将其显示为数字。 4. 也是一个数字,但这个命令告诉它不是一个数字。
【解决方案9】:
if echo $var | egrep -q '^[0-9]+$'

实际上,如果 var 是多行,这不起作用。

var="123
qwer"

特别是如果 var 来自文件:

var=`cat var.txt`

这是最简单的:

if [ "$var" -eq "$var" ] 2> /dev/null
then echo yes
else echo no
fi

【讨论】:

  • 对重复 Piotr 的 2008 年回答而没有署名的轻微反对。与那个问题相同的误报问题(添加-n "$var" 以捕获空/未设置的变量)。见那里的cmets。关于多行问题的潜在误报的好点。
【解决方案10】:

这里是没有任何正则表达式的测试(tcsh 代码):

创建文件校验码:

#! /usr/bin/env tcsh
if ( "$*" == "0" ) then
    exit 0 # number
else
    ((echo "$*" | bc) > /tmp/tmp.txt) >& /dev/null
    set tmp = `cat /tmp/tmp.txt`
    rm -f /tmp/tmp/txt
    if ( "$tmp" == "" || $tmp == 0 ) then
        exit 1 # not a number
    else
        exit 0 # number
    endif

endif

然后运行

chmod +x checknumber

使用

checknumber -3.45

你会得到错误级别的结果 ($?)。

您可以轻松优化它。

【讨论】:

  • 叉子很重。除非您只有 csh,否则整数存在较轻的实现(请参阅以前的答案)。稍微支持处理浮点数,虽然我猜这不是 OP 想要的(OP 在问题描述上很模糊)。
【解决方案11】:
( test ! -z "$num" && test "$num" -eq "$num" 2> /dev/null ) && {
   # $num is a number
}

【讨论】:

  • 这将失败,因为lack of quoting 用于任何重要的字符串输入。
  • @tripleee 已修复
  • -z 检查真的有必要吗? test "" -eq "" 2>/dev/null 符合我的预期(标准 macOS 上的旧 Bash 3.2)。无论如何,括号似乎是多余的(并且会花费您不必要的子shell)。
【解决方案12】:

您可以使用简单的测试命令来做到这一点。

$ test ab -eq 1 >/dev/null 2>&1
$ echo $?
2

$ test 21 -eq 1 >/dev/null 2>&1
$ echo $?
1

$ test 1 -eq 1 >/dev/null 2>&1
$ echo $?
0

所以如果退出状态是 0 或 1 则它是一个整数,但如果存在状态是 2 则它不是一个数字。

【讨论】:

  • 投反对票 - 与@Piotr 2008 年的回答基本相同。没有人在回复之前查看现有答案 - 尤其是在同一个线程中(更不用说其他类似的线程)?
【解决方案13】:
a=123
if [ `echo $a | tr -d [:digit:] | wc -w` -eq 0 ]
then
    echo numeric
else
    echo ng
fi

数字

a=12s3
if [ `echo $a | tr -d [:digit:] | wc -w` -eq 0 ]
then
    echo numeric
else
    echo ng
fi

ng

【讨论】:

  • 您能补充一下您的解决方案吗?
  • @StevenWestbrook:这会从 $a 中删除数字并计算剩余的数字。如果还有任何东西,它就不是一串只有数字的字符串(“非数字”)。
  • 不处理负数(例如,-123、--123)。不幸的是,使用这种 fork-heavy 方法添加对负数的支持意味着我认为在管道中添加另一个 tr -d -
  • 您可以将 tr(1) 表达式更改为 '[[:digit:]-]' 以捕获负数(或将 [:xdigit:] 用于基数为 16 的数字),但这给出了123-54 之类的误报(认为这是一个有效数字)。
【解决方案14】:

从命令行获取值并显示 THE INPUT IS DECIMAL/NON-DECIMAL 和 NUMBER 与否:

NUMBER=$1

            IsDecimal=`echo "$NUMBER" | grep "\."`

if [ -n "$IsDecimal" ]
then
            echo "$NUMBER is Decimal"
            var1=`echo "$NUMBER" | cut -d"." -f1`
            var2=`echo "$NUMBER" | cut -d"." -f2`

            Digit1=`echo "$var1" | egrep '^-[0-9]+$'`
            Digit2=`echo "$var1" | egrep '^[0-9]+$'`
            Digit3=`echo "$var2" | egrep '^[0-9]+$'`


            if [ -n "$Digit1" ] && [ -n "$Digit3" ]
            then
                echo "$NUMBER is a number"
            elif [ -n "$Digit2" ] && [ -n "$Digit3" ]
            then
                echo "$NUMBER is a number"

            else
                echo "$NUMBER is not a number"
            fi
else
            echo "$NUMBER is not Decimal"

            Digit1=`echo "$NUMBER" | egrep '^-[0-9]+$'`
            Digit2=`echo "$NUMBER" | egrep '^[0-9]+$'`

            if [ -n "$Digit1" ] || [ -n "$Digit2" ]; then
                echo "$NUMBER is a number"
            else
                echo "$NUMBER is not a number"
            fi
fi

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-10-20
    • 1970-01-01
    • 2011-03-30
    • 1970-01-01
    • 2013-11-16
    • 1970-01-01
    • 2012-09-21
    • 2015-04-17
    相关资源
    最近更新 更多