To test if a variable is a number in Bash, you can use regular expressions, arithmetic evaluation, or external tools like grep
or awk
. Below are detailed methods with examples, covering integers, floating-point numbers, and edge cases.
1. Using Regular Expressions (Most Flexible)
Check if the variable matches a numeric pattern using Bash’s [[ =~ ]]
operator.
Example 1: Check for Integers
var="12345"
if [[ $var =~ ^-?[0-9]+$ ]]; then
echo "$var is an integer"
else
echo "$var is NOT an integer"
fi
Example 2: Check for Integers or Floats
var="-3.14"
if [[ $var =~ ^-?[0-9]+([.][0-9]+)?$ ]]; then
echo "$var is a number"
else
echo "$var is NOT a number"
fi
Example 3: Handle Leading/Trailing Spaces
Trim spaces before checking:
var=" 42 "
trimmed_var=$(echo "$var" | xargs) # Remove whitespace
if [[ $trimmed_var =~ ^-?[0-9]+([.][0-9]+)?$ ]]; then
echo "$trimmed_var is a number"
fi
2. Arithmetic Evaluation (Integers Only)
Use arithmetic expansion (( ... ))
to test if the variable is an integer.
Limitation: Fails for floating-point numbers.
var="123"
if (( var + 0 )) 2>/dev/null; then
echo "$var is an integer"
else
echo "$var is NOT an integer"
fi
Edge Case Handling
var="abc"
if (( var + 0 )) 2>/dev/null; then
echo "Valid integer"
else
echo "Invalid integer" # Triggers for non-integers
fi
3. Using case
Statements
Pattern-match numeric values with case
:
var="123.45"
case $var in
'' | *[!-.0-9]*) echo "$var is NOT a number" ;;
*) echo "$var is a number" ;;
esac
Improved case
for Floats
var="-123.45"
case $var in
-*) num_part="${var#-}" ;; # Handle negatives
*) num_part="$var" ;;
esac
case $num_part in
'' | .* | *.*.* | *[!0-9.]*) echo "$var is invalid" ;;
*) echo "$var is valid" ;;
esac
4. Using External Tools (e.g., grep
or awk
)
Check with grep
:
var="42"
if echo "$var" | grep -Eq '^-?[0-9]+$'; then
echo "$var is an integer"
fi
Check for Floats with grep
:
var="3.14"
if echo "$var" | grep -Eq '^-?[0-9]+(\.[0-9]+)?$'; then
echo "$var is a float"
fi
Check with awk
:
var="123"
if awk -v var="$var" 'BEGIN {exit !(var ~ /^-?[0-9]+$/)}'; then
echo "$var is an integer"
fi
Handling Edge Cases
Case | Example | Solution |
---|---|---|
Leading zeros | 00123 | Use regex ^-?[0-9]+$ (allowed). |
Scientific notation | 1.2e3 | Extend regex to ^-?[0-9]+(\.[0-9]+)?([eE][+-]?[0-9]+)?$ . |
Empty/undefined var | var="" | Check [[ -z "$var" ]] before numeric tests. |
Commas as decimals | 3,14 | Adjust regex: ^-?[0-9]+([,.][0-9]+)?$ (locale-specific). |
Leading/trailing chars | abc123 | Ensure regex anchors (^ and $ ) to reject non-numeric characters. |
Full Example: Validate Integer or Float
is_number() {
local var="$1"
# Check for integer or float (including negatives and decimals)
[[ $var =~ ^-?[0-9]+([.][0-9]+)?$ ]] || [[ $var =~ ^-?[.][0-9]+$ ]]
}
var="-123.45"
if is_number "$var"; then
echo "$var is valid"
else
echo "$var is invalid"
fi
Key Notes
- Regex Anchors: Use
^
(start) and$
(end) to ensure the entire string is numeric. - Quotes: Always quote variables (e.g.,
"$var"
) to handle spaces and special characters. - Floats: Use
[.][0-9]+
to validate decimals (e.g.,3.14
,.5
,123.
is invalid). - Performance: Regex (
[[ =~ ]]
) is faster than external tools likegrep
.
Choose the method that best fits your use case!