1

The following program checks if the first parameter is a number, or a not a number. The best I could come up with so far is:

#/bin/bash
if (( $# )) && (( $1 != 0 )) ; then
    echo "number"
else
    echo "not number"
fi
  • This works for numbers like 1, -1, 100, etc, for strings a, abc, a431, or if no parameter is given.

  • It works with a warning for strings like 1a1, 1.3, -1.2

  • But FAILS (obviously) if the parameter is 0

How could this be fixed? (using arithmetic expressions)

Related: Bash integer comparison

1

5 Answers 5

2

You can press the printf built-in command to do the job:

if printf "%d" ${1:-foo} > /dev/null; then
    echo "number"
else
    echo "NOT a number"
fi

printf exits with non-zero status if the conversion fails. The ${1-...} notation provides a known not-number if $1 isn't set.

Sign up to request clarification or add additional context in comments.

Comments

1

You could use a regex:

#/bin/bash

if [[ "$1" =~ ^-?[0-9]+$ ]] ; then
    echo "number"
else
    echo "not number"
fi

If you wanted it to handle floating point, you could tweak it easily enough:

#/bin/bash

if [[ "$1" =~ ^-?[0-9]+$ || "$1" =~ ^-?[0-9]*\.[0-9]+ ]] ; then
    echo "number"
else
    echo "not number"
fi

1 Comment

yes this passes all the test I could think of. Not accepting yet though waiting for better answers (if any).
1

I would rather use something like

if [ $1 = "$(echo $1 | awk '{print strtonum($0)}')" ]; then
echo "number"
else
echo "not number"
fi

2 Comments

Yes this would work. But I will give it some time in case someone will be able to solve it with the above constrains.
Also it throws a warning if no parameter is given and identifies floats as numbers
1

Solution using extended globs

#/bin/bash
shopt -s extglob
if [[ $1 = *[0-9]* && $1 = ?([+-])*([0-9])?(.*([0-9])) ]]; then
    echo "Is a number"
else
    echo "Not a number"
fi

Output

$ ./test -1
Is a number
$ ./test 0
Is a number
$ ./test 1
Is a number
$ ./test a
Not a number
$ ./test -1.2
Is a number
$ ./test 0.0
Is a number
$ ./test 1.2
Is a number
$ ./test a.b
Not a number

4 Comments

Plus 1 for prompting more people to Google extended globbing. Minus 1 (IMHO) for the additional complexity, and a regex-style matcher that can't be directly translated if the script gets ported to something other than Bash. Granted, YMMV.
I disagree, this solution is no more complex or harder to port than yours.
Globbing is Bash-only syntax that doesn't quite match standard regex structure. I didn't say it was vastly more difficult, just that there's a certain utility in KISS when you don't specifically need Bash-specific features, and can use a generalized regex structure instead.
But not to worry, it's not like an answer is going to be chosen on this question anyway. :-)
1

Might be easier to test for what is not a number:

if (( $# )) ; then
  if [[ $1 == *[^0-9]* ]] ; then
    echo "Not a number"
  else
    echo "Is a number"
  fi
fi

Note that the above is actually testing only for positive integers. Add +-. to the character class and it will work, sort of, for positive/negative integers and decimal fractions. I say sort of because it would pass 123.456.789 as a number, but it's not valid. You'd need to add additional logic to weed out misplaced or multiple signs and decimal points (and strings like "+", ".", etc.).

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.