[unix] Check that a variable is a number in UNIX shell

How do I check to see if a variable is a number, or contains a number, in UNIX shell?

This question is related to unix shell

The answer is


Here is the test without any regular expressions (tcsh code):

Create a file checknumber:

#! /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

and run

chmod +x checknumber

Use

checknumber -3.45

and you'll got the result as errorlevel ($?).

You can optimise it easily.


if echo $var | egrep -q '^[0-9]+$'

Actually this does not work if var is multiline.

ie

var="123
qwer"

Especially if var comes from a file :

var=`cat var.txt`

This is the simplest :

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

INTEGER

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

tests (with var=2 etc.):

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

NUMBER

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

tests (with var=2 etc.):

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

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

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

numeric

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

ng


( test ! -z $num && test $num -eq $num 2> /dev/null ) && {
   # $num is a number
}

Taking the value from Command line and showing THE INPUT IS DECIMAL/NON-DECIMAL and NUMBER or not:

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

Here's a version using only the features available in a bare-bones shell (ie it'd work in sh), and with one less process than using grep:

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

This checks that the $var represents only an integer; adjust the regexp to taste, and note that the expr regexp argument is implicitly anchored at the beginning.


Shell variables have no type, so the simplest way is to use the return type test command:

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

(Or else parse it with a regexp)


I'm kind of newbee on shell programming so I try to find out most easy and readable It will just check the var is greater or same as 0 I think it's nice way to choose parameters... may be not what ever... :

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

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

You can do that with simple test command.

$ 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

So if the exit status is either 0 or 1 then it is a integer , but if the exis status is 2 then it is not a number.


Shell variables have no type, so the simplest way is to use the return type test command:

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

(Or else parse it with a regexp)


No forks, no pipes. Pure POSIX shell:

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

(Assumes number := a string of digits). If you want to allow signed numbers with a single leading - or + as well, strip the optional sign like this:

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

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

Here is the test without any regular expressions (tcsh code):

Create a file checknumber:

#! /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

and run

chmod +x checknumber

Use

checknumber -3.45

and you'll got the result as errorlevel ($?).

You can optimise it easily.


In either ksh93 or bash with the extglob option enabled:

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

This can be checked using regular expression.

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

No forks, no pipes. Pure POSIX shell:

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

(Assumes number := a string of digits). If you want to allow signed numbers with a single leading - or + as well, strip the optional sign like this:

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

This can be checked using regular expression.

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

if echo $var | egrep -q '^[0-9]+$'

Actually this does not work if var is multiline.

ie

var="123
qwer"

Especially if var comes from a file :

var=`cat var.txt`

This is the simplest :

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

I'm kind of newbee on shell programming so I try to find out most easy and readable It will just check the var is greater or same as 0 I think it's nice way to choose parameters... may be not what ever... :

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

You can do that with simple test command.

$ 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

So if the exit status is either 0 or 1 then it is a integer , but if the exis status is 2 then it is not a number.


In either ksh93 or bash with the extglob option enabled:

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

Shell variables have no type, so the simplest way is to use the return type test command:

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

(Or else parse it with a regexp)


Taking the value from Command line and showing THE INPUT IS DECIMAL/NON-DECIMAL and NUMBER or not:

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

In either ksh93 or bash with the extglob option enabled:

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

Here's a version using only the features available in a bare-bones shell (ie it'd work in sh), and with one less process than using grep:

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

This checks that the $var represents only an integer; adjust the regexp to taste, and note that the expr regexp argument is implicitly anchored at the beginning.


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

Shell variables have no type, so the simplest way is to use the return type test command:

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

(Or else parse it with a regexp)


INTEGER

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

tests (with var=2 etc.):

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

NUMBER

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

tests (with var=2 etc.):

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

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

numeric

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

ng


In either ksh93 or bash with the extglob option enabled:

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