25

I would like to test if my variable $var is actually an integer or not. How can I please do that?

codeforester
  • 39,467
  • 16
  • 112
  • 140
Jary
  • 1,223
  • 2
  • 11
  • 7

7 Answers7

25

As long as you're using bash version >=3 you can use a regular expression:

[[ $a =~ ^-?[0-9]+$ ]] && echo integer

While this bash FAQ mentions inconsistencies in the bash regex implementation in various bash 3.x (should the regex be quoted or not), I think in this case, there are no characters that need quoting in any version, so we are safe. At least it works for me in:

  • 3.00.15(1)-release (x86_64-redhat-linux-gnu)
  • 3.2.48(1)-release (x86_64-apple-darwin12)
  • 4.2.25(1)-release (x86_64-pc-linux-gnu)
$ a=""
$ [[ $a =~ ^-?[0-9]+$ ]] && echo integer
$ a=" "
$ [[ $a =~ ^-?[0-9]+$ ]] && echo integer
$ a="a"
$ [[ $a =~ ^-?[0-9]+$ ]] && echo integer
$ a='hello world!'
$ [[ $a =~ ^-?[0-9]+$ ]] && echo integer
$ a='hello world 42!'
$ [[ $a =~ ^-?[0-9]+$ ]] && echo integer
$ a="42"
$ [[ $a =~ ^-?[0-9]+$ ]] && echo integer
integer
$ a="42.1"
$ [[ $a =~ ^-?[0-9]+$ ]] && echo integer
$ a="-42"
$ [[ $a =~ ^-?[0-9]+$ ]] && echo integer
integer
$ a="two"
$ [[ $a =~ ^-?[0-9]+$ ]] && echo integer
Alex
  • 2,000
  • 4
  • 23
  • 41
Digital Trauma
  • 15,475
  • 3
  • 51
  • 83
8

A hackish-but-portable solution is to compare the value with itself using test's -eq (integer equality) operator and throw away any resulting error message:

is_int () { test "$@" -eq "$@" 2> /dev/null; }

for input in "0.3" "abc" "3"; do
    if is_int "$input"; then
        echo "Integer: $input"
    else
        echo "Not an integer: $input"
    fi
done
Foobie Bletch
  • 214
  • 1
  • 9
yabt
  • 81
  • 1
  • From what I see, there is no need to redirect fd2 to `/dev/null`. Also this works nicely on empty strings. It is also POSIX compliant. Very clean, but hacky. – kvantour Apr 13 '22 at 07:16
6

I was needing something that would return true only for positive integers (and fail for the empty string). I settled on this:

test -n "$1" -a "$1" -ge 0 2>/dev/null

the 2>/dev/null is there because test prints an error (and returns 2) if an input (to -ge) doesn't parse as an integer

I wish it could be shorter, but "test" doesn't seem to have a "quiet" option and treats "" as a valid integer (zero).

JasonWoof
  • 4,176
  • 1
  • 19
  • 28
2
shopt -s extglob
case "$var" in
 +([0-9]) ) echo "integer";
esac
ghostdog74
  • 327,991
  • 56
  • 259
  • 343
1

echo your_variable_here | grep "^-\?[0-9]*$" will return the variable if it is an integer and return nothing otherwise.

ashastral
  • 2,818
  • 1
  • 21
  • 32
  • 2
    Actually it will also print out the variable to stdout if it's an integer. You really want `grep -q`, which doesn't print to stdout, it only exits with 0 or non-0 if there is a match. – Adam Rosenfield Sep 02 '10 at 03:57
1

You can do this:

shopt -s extglob

if [ -z "${varname##+([0-9])}" ]
then
  echo "${varname} is an integer"
else
  echo "${varname} is not an integer"
fi

The ## greedily removes the regular expression from the value returned by "varname", so if the var is an integer it is true, false if not.

It has the same weakness as the top answer (using "$foo != [!0-9]"), that if $varname is empty it returns true. I don't know if that's valid. If not just change the test to:

if [ -n "$varname" ] && [ -z "${varname##[0-9]}" ]
Aurelio De Rosa
  • 21,856
  • 8
  • 48
  • 71
Svend Hansen
  • 3,277
  • 3
  • 31
  • 50
  • (just noticed a bug in the above where it says 1a1 is an integer :P ... one sec) – Svend Hansen Mar 28 '12 at 09:11
  • I can't figure out the "filename expansion" way of writing "one or more of patter xxx". So when I write [0-9]* it matches an integer followed by any character, so "1a1", "1a" or "1blah" all match... With a test like in the FAQ linked to it could be done as: `if [[ "$varname" == +([0-9]) ]]` but the '[[' aren't standard BASH and must be using "proper" regular expression expansion rather than the file expansion. Anyone know how to make my solution work? :P – Svend Hansen Mar 28 '12 at 09:44
  • ghostdog74's solution gave me the answer. Adding `shopt -s extglob` I guess enables the desired pattern syntax :) – Svend Hansen Mar 28 '12 at 09:50
0

You can perform a *2 /2 operation that check both if value is numeric and is integer. The operation returns 0 if not numeric

echo "Try with 10"

var=10
var1=`echo $((($var*2)/2))`

if [ "$var" == "$var1" ]; then
  echo '$var integer'
else
  echo '$var not integer'
fi

echo "Try with string"

var=string
var1=`echo $((($var*2)/2))`

if [ "$var" == "$var1" ]; then
  echo '$var integer'
else
  echo '$var not integer'
fi
  • Exact duplicate of http://stackoverflow.com/questions/2210349/bash-test-whether-string-is-valid-as-an-integer/21884506#21884506 – Paresh Mayani Feb 20 '14 at 10:09