39

I'm trying to check if an input is an integer and I've gone over it a hundred times but don't see the error in this. Alas it does not work, it triggers the if statement for all inputs (numbers/letters)

read scale
if ! [[ "$scale" =~ "^[0-9]+$" ]]
        then
            echo "Sorry integers only"
fi

I've played around with the quotes but either missed it or it did nothing. What do I do wrong? Is there an easier way to test if an input is just an INTEGER?

36

Remove quotes

if ! [[ "$scale" =~ ^[0-9]+$ ]]
    then
        echo "Sorry integers only"
fi
| improve this answer | |
  • stackoverflow.com/questions/806906/… had the quotes backwards – lonewarrior556 Aug 22 '14 at 17:52
  • 1
    So there is a bug. With quotes the regexp is treated as a literal string. One can check that with scale='^[0-9]+$'; [[ "$scale" == "^[0-9]+$" ]] && echo equal || echo "not equal" – jimmij Aug 22 '14 at 18:13
20

Use -eq operator of test command:

read scale
if ! [ "$scale" -eq "$scale" ] 2> /dev/null
then
    echo "Sorry integers only"
fi

It not only works in bash but also any POSIX shell. From POSIX test documentation:

n1 -eq  n2
    True if the integers n1 and n2 are algebraically equal; otherwise, false.
| improve this answer | |
  • that checks if its any number, not just integers – lonewarrior556 Aug 22 '14 at 17:27
  • 2
    @lonewarrior556: It works only for integer, see: pubs.opengroup.org/onlinepubs/9699919799/utilities/test.html. I guess you said for any number because you use new test [[ instead of old test [ as mine. – cuonglm Aug 22 '14 at 17:27
  • 1
    Good idea but a bit noisy. I would rather not have to redirect errors to dev null. – Wildcard Oct 16 '16 at 8:09
  • 2
    @Wildcard: Yep, we pay it for portability. – cuonglm Oct 16 '16 at 8:13
8

For unsigned integers I use:

read -r scale
[ -z "${scale//[0-9]}" ] && [ -n "$scale" ] || echo "Sorry integers only"

Tests:

$ ./test.sh
7
$ ./test.sh
   777
$ ./test.sh
a
Sorry integers only
$ ./test.sh
""
Sorry integers only
$ ./test.sh

Sorry integers only
| improve this answer | |
  • 1
    I like that one as it is made with builtins, fast, and seems quite posix... I tried on an old shell (bash 2.0.5) and it works perfectly. – Olivier Dulac Apr 5 '18 at 18:08
  • What about spaces inside the argument? Like ” 086 “. – 0andriy Oct 3 '18 at 23:18
  • @0andriy See the second test. – raciasolvo Oct 5 '18 at 16:58
8

As the OP seems to want only positive integers:

[ "$1" -ge 0 ] 2>/dev/null

Examples:

$ is_positive_int(){ [ "$1" -ge 0 ] 2>/dev/null && echo YES || echo no; }
$ is_positive_int word
no
$ is_positive_int 2.1
no
$ is_positive_int -3
no
$ is_positive_int 42
YES

Note that a single [ test is required:

$ [[ "word" -eq 0 ]] && echo word equals zero || echo nope
word equals zero
$ [ "word" -eq 0 ] && echo word equals zero || echo nope
-bash: [: word: integer expression expected
nope

This is because dereferencing occurs with [[:

$ word=other
$ other=3                                                                                                                                                                                  
$ [[ $word -eq 3 ]] && echo word equals other equals 3
word equals other equals 3
| improve this answer | |
4
( scale=${scale##*[!0-9]*}
: ${scale:?input must be an integer}
) || exit

That does the check and outputs your error.

| improve this answer | |
  • OPTIND is good here, too. just saiyan. – mikeserv Oct 29 '18 at 11:06
  • By far the best answer yet too many people don't use parameter expansion. This works on arrays too, incl $@: params=("${@##*[!0-9]*}") -- Keep all positional arguments, but only use numbers - anything else will be converted to null string which conveniently evaluates to 0 in arithmetic evaluations (my use case - function parameter is a list of integers, unset or null should default to 0 but caller sets variable name when unset). – Thomas Guyot-Sionnest Apr 21 at 22:10
2

Please check How do I test if a variable is a number in Bash stackoverflow page. This page have some other good ways for checking integer number.

| improve this answer | |
2

A POSIX and portable solution is:

read scale
if     [ -z "${scale##*[!0-9]*}" ]; 
then   echo "Sorry integers only"
fi
| improve this answer | |
  • 1
    By far the best answer yet too many people don't use parameter expansion. This works on arrays too, incl $@: params=("${@##*[!0-9]*}") -- Keep all positional arguments, but only use numbers - anything else will be converted to null string which conveniently evaluates to 0 in arithmetic evaluations (my use case - function parameter is a list of integers, unset or null should default to 0 but caller sets variable name when unset). – Thomas Guyot-Sionnest Apr 22 at 13:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.