Most scripts eventually need a bash numeric comparison: bash compare variable to
number, bash greater than / less than between two counters, or a quick bash integer
comparison before doing work. Bash only does integer math in [[ / [ /
(( )) the way people expect; decimals need something like bc. The patterns below
are the ones I reach for daily, plus a few footguns (leading zeros, empty variables,
using < as a redirect inside [).
Tested all the commands and code from this article on Ubuntu 25.04, kernel 6.14.0-37-generic, Bash 5.2.37.
Integer operators (compare numbers in Bash)
These operators expect integers (optionally with a leading -). They work inside
[ ... ], [[ ... ]], and test ....
| Operator | Meaning | Example |
|---|---|---|
-eq |
equal | [[ $a -eq $b ]] |
-ne |
not equal | [[ $a -ne $b ]] |
-lt |
less than | [[ $a -lt $b ]] |
-le |
less or equal | [[ $a -le $b ]] |
-gt |
greater than | [[ $a -gt $b ]] |
-ge |
greater or equal | [[ $a -ge $b ]] |
Bash compare variable to number with [[ or [
Quote variables so empty values do not break the parser. Comparing a variable to a literal is the same as comparing two variables:
count=3
if [[ "$count" -eq 3 ]]; then
echo "count is exactly three"
fi[[ is a Bash keyword: you can combine tests with && / || without extra brackets,
and you avoid some classic [ footguns. [ / test is still what you want when the
shebang is plain sh on a minimal system.
a=5
b=10
if [ "$a" -lt "$b" ]; then
echo "a is less than b"
fiOutput from that snippet:
a is less than bSame check with [[:
a=5
b=10
if [[ $a -lt $b ]]; then
echo "a is less than b"
fiSame line on stdout:
a is less than bBash if numeric comparison with (( ))
Inside (( ... )), Bash treats the interior as arithmetic. You can use C-style
operators (<, <=, ==, !=, >, >=) and skip $ on simple variable names:
a=5
b=10
if (( a < b )); then
echo "a is less than b"
fiThat prints:
a is less than b(( )) exits 1 when the expression evaluates to zero, which is handy for
while (( i < n )) style loops. For “compare numbers in bash” when the math gets
longer, (( )) tends to read cleaner than a chain of -lt / -gt.
The test builtin
test and [ are the same family. This is portable and boring in a good way:
a=5
b=10
if test "$a" -lt "$b"; then
echo "a is less than b"
fiOutput:
a is less than bBranching and loops
For branching, pair numeric tests with normal if / else flow. Timing or logging comparisons in real scripts often sits next to ideas from get script execution time.
a=20
b=10
if [ "$a" -gt "$b" ]; then
echo "a is greater than b"
else
echo "a is not greater than b"
fiWhat I get:
a is greater than bwhile and until
Bash compare integers in a loop by re-testing the condition each iteration:
a=1
while [ "$a" -lt 5 ]; do
echo "Number is $a"
((a++))
doneOutput:
Number is 1
Number is 2
Number is 3
Number is 4until flips the sense (run while the test is false):
a=0
until [ "$a" -ge 5 ]; do
echo "Number is $a"
((a++))
doneOutput:
Number is 0
Number is 1
Number is 2
Number is 3
Number is 4More loop shapes live in the dedicated while write-up if you need them.
Pitfalls worth memorizing
Leading zeros and “value too great for base”
Arithmetic treats numbers with a leading 0 as octal. 08 is invalid octal, so
both [[ and (( )) can error:
a=08
b=8
[[ $a -eq $b ]] 2>&1 || trueTypical stderr:
bash: [[: 08: value too great for base (error token is "08")Strip leading zeros, read fields with 10# in arithmetic ($((10#$a))), or avoid
padding unless you control the format.
Do not use < or > inside [ for integers
Inside [, < and > are redirection, not “less than”. Even in [[, use -lt
/ -gt for integer relations; < / > there compare strings in collation order,
which is not the same as numeric order for multi-digit values.
Numeric check:
[[ 9 -lt 10 ]] && echo "numeric nine is less than ten"Lexicographic pitfall (string rules, not counting):
[[ 9 < 10 ]] && echo "would be wrong for integers" || echo "string compare did not say 9 < 10"On my shell that prints:
numeric nine is less than ten
string compare did not say 9 < 10Empty or unset variables
[[ "$n" -eq 5 ]] is safe when n is empty (it is treated as 0 for the numeric
context in recent Bash, but the clearer habit is [[ -n "$n" ]] && [[ "$n" -eq 5 ]]
or default the value: n=${n:-0}).
Floating point
Bash arithmetic is integer-only. For decimals, call bc, awk, or Python — do not
pretend 3.14 works inside -eq.
Summary
Bash numeric comparison comes down to picking an integer form: [[ "$a" -gt "$b" ]]
and friends for clarity and combining conditions, (( a > b )) when the expression
already looks like arithmetic, and test / [ when you care about POSIX sh.
Comparing a variable to a literal uses the same operators—keep operands quoted, use
-eq / -lt / -gt instead of < / > for real integer relations, watch leading
zeros in values like 08, and use bc or awk when you need decimals. With that,
if branches and loops over integers stop being guesswork.
Further reading:

