26

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?

20

Remove quotes

if ! [[ "$scale" =~ ^[0-9]+$ ]]
    then
        echo "Sorry integers only"
fi
  • stackoverflow.com/questions/806906/… had the quotes backwards – lonewarrior556 Aug 22 '14 at 17:52
  • 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
13

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.
  • 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
  • Good idea but a bit noisy. I would rather not have to redirect errors to dev null. – Wildcard Oct 16 '16 at 8:09
  • 1
    @Wildcard: Yep, we pay it for portability. – cuonglm Oct 16 '16 at 8:13
5

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
4

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
  • 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
2
( scale=${scale##*[!0-9]*}
: ${scale:?input must be an integer}
) || exit

That does the check and outputs your error.

  • OPTIND is good here, too. just saiyan. – mikeserv Oct 29 '18 at 11:06
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.

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.