Differences between revisions 1 and 6 (spanning 5 versions)
Revision 1 as of 2007-05-02 23:46:43
Size: 1429
Editor: redondos
Comment:
Revision 6 as of 2007-07-28 04:53:56
Size: 2698
Editor: ppp020-014
Comment: add matching with extglob
Deletions are marked like this. Additions are marked like this.
Line 23: Line 23:
If what you actually mean is "a valid floating-point number" or something else more complex, then you might prefer to use a regular expression. Bash version 3 and above have regular expression support in the [[ command: If what you actually mean is "a valid floating-point number" or something else more complex, then you might prefer to use a regular expression. Here is a portable version, using {{{egrep}}}:
Line 26: Line 26:
if [[ $foo =~ ^[-+]?[0-9]+\(\.[0-9]+\)?$ ]]; then if test "$foo" && echo "$foo" | egrep '^[-+]?[0-9]*(\.[0-9]+)?$' >/dev/null; then
    echo "'$foo' might be a number"
else
    echo "'$foo' might not be a number"
fi
}}}

The leading test of {{{"$foo"}}} is to ensure that it is not an empty string. (An empty string would satisfy the regex, and changing the regex to avoid that is not worth the effort.)

Bash version 3 and above have regular expression support in the [[ command. However, due to serious bugs and syntax changes in Bash's [[ regex support, we '''do not recommend''' using it. Nevertheless, if I simply omit all Bash regex answers here, someone will come along and fill them in -- and they probably won't work, or won't contain all the caveats necessary. So, in the interest of preventing disasters, here are the Bash regex answers that you should not use.

{{{
if [[ $foo && $foo =~ ^[-+]?[0-9]*\(\.[0-9]+\)?$ ]]; then # Bash 3.1 only!
Line 33: Line 45:
If you don't have bash version 3, then you would use {{{egrep}}}: Unfortunately, bash changed the syntax of its regular expression support after version 3.1, so the following ''may'' work in some patched versions of bash 3.2:
Line 36: Line 48:
if echo "$foo" | egrep '^[-+]?[0-9]+(\.[0-9]+)?$' >/dev/null; then
    echo "'$foo' might be a number"
if [[ $foo && $foo =~ ^[-+]?[0-9]*(\.[0-9]+)?$ ]]; then    # **PATCHED** Bash 3.2 only!
    echo "'$foo' looks rather like a number"
Line 39: Line 51:
    echo "'$foo' might not be a number"     echo "'$foo' doesn't look particularly numeric to me"
Line 43: Line 55:
Note that the parentheses in the {{{egrep}}} regular expression don't require backslashes in front of them, whereas the ones in the bash3 command do. It fails rather spectacularly in bash 3.1 and in bash 3.2 without patches.

Note that the parentheses in the {{{egrep}}} regular expression and the bash 3.2.patched regular expression don't require backslashes in front of them, whereas the ones in the bash 3.1 command do.

Another possibility with bash is perhaps to use extglob:
{{{
shopt -s extglob
[[ +1234.43 = *([+-])+([0-9])*(.+([0-9])) ]] && echo "this is a number"
}}}

Anchor(faq54)

How can I tell whether a variable contains a valid number?

First, you have to define what you mean by "number". The most common case seems to be that, when people ask this, they actually mean "a non-negative integer, with no leading + sign".

if [[ $foo = *[^0-9]* ]]; then
   echo "'$foo' has a non-digit somewhere in it"
else
   echo "'$foo' is strictly numeric"
fi

This can be done in Korn and legacy Bourne shells as well, using case:

case "$foo" in
    *[!0-9]*) echo "'$foo' has a non-digit somewhere in it" ;;
    *) echo "'$foo' is strictly numeric" ;;
esac

If what you actually mean is "a valid floating-point number" or something else more complex, then you might prefer to use a regular expression. Here is a portable version, using egrep:

if test "$foo" && echo "$foo" | egrep '^[-+]?[0-9]*(\.[0-9]+)?$' >/dev/null; then
    echo "'$foo' might be a number"
else
    echo "'$foo' might not be a number"
fi

The leading test of "$foo" is to ensure that it is not an empty string. (An empty string would satisfy the regex, and changing the regex to avoid that is not worth the effort.)

Bash version 3 and above have regular expression support in the [[ command. However, due to serious bugs and syntax changes in Bash's [[ regex support, we do not recommend using it. Nevertheless, if I simply omit all Bash regex answers here, someone will come along and fill them in -- and they probably won't work, or won't contain all the caveats necessary. So, in the interest of preventing disasters, here are the Bash regex answers that you should not use.

if [[ $foo && $foo =~ ^[-+]?[0-9]*\(\.[0-9]+\)?$ ]]; then  # Bash 3.1 only!
    echo "'$foo' looks rather like a number"
else
    echo "'$foo' doesn't look particularly numeric to me"
fi

Unfortunately, bash changed the syntax of its regular expression support after version 3.1, so the following may work in some patched versions of bash 3.2:

if [[ $foo && $foo =~ ^[-+]?[0-9]*(\.[0-9]+)?$ ]]; then    # **PATCHED** Bash 3.2 only!
    echo "'$foo' looks rather like a number"
else
    echo "'$foo' doesn't look particularly numeric to me"
fi

It fails rather spectacularly in bash 3.1 and in bash 3.2 without patches.

Note that the parentheses in the egrep regular expression and the bash 3.2.patched regular expression don't require backslashes in front of them, whereas the ones in the bash 3.1 command do.

Another possibility with bash is perhaps to use extglob:

shopt -s extglob
[[ +1234.43 = *([+-])+([0-9])*(.+([0-9])) ]] && echo "this is a number"

BashFAQ/054 (last edited 2022-08-01 10:02:57 by 89)