| Tested on | RHEL 10.2 (Coughlan) |
|---|---|
| Package | bash 5.2.26-6.el10bc 1.08.2-5.el10gawk 5.3.0-8.el10 |
| Applies to | Linux distributions with Bash installed |
| Privilege | Normal user |
| Scope | Integer comparison with -eq, -ne, -gt, -ge, -lt, -le in [ ] and [[ ]], arithmetic conditions in (( )), leading zeros and 10#, negative numbers, validating untrusted input, and decimal comparison with bc or awk. General arithmetic and calculation patterns are in the Bash arithmetic guide. |
| Related guides | Bash shell script tutorial Shell scripting course hub |
Bash provides several ways to compare integers: [ … ], [[ … ]], and arithmetic (( … )). Decimal values need a tool such as bc or awk — Bash integer forms cannot compare 3.14 directly.
For string equality and pattern tests, see compare strings in Bash.
Bash Numeric Comparison — Quick Answer
| Goal | Use |
|---|---|
POSIX sh portability |
[ "$a" -gt "$b" ] |
Bash-only integer test in one [[ ]] block |
[[ "$a" -gt "$b" ]] |
| C-style arithmetic conditions | (( a > b )) |
| Decimal values | bc or awk — not -eq / (( )) alone |
Inside [[ … ]], < and > compare strings. For numbers, use -lt / -gt, or switch to (( a < b )).
Quote variable expansions inside [ … ]. Inside [[ … ]], quoting simple operands is optional because normal word splitting and pathname expansion are disabled. Inside (( … )), simple names can omit $.
Bash Numeric Comparison Operators
-eq, -ne, -lt, -le, -gt, and -ge perform numeric comparisons. In [ … ] and test, operands must represent integers. In [[ … ]], Bash evaluates the operands as arithmetic expressions:
| 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" ]] |
Inside [ … ] and [[ … ]], use -eq and -ne for numeric equality. = and == are string-comparison operators in conditional syntax. Inside (( … )), use == and != for arithmetic equality.
Compare Numbers with [ ]
[ is the test command. Quote variable expansions so empty values or spaces do not change the arguments passed to test:
a=5
b=10
if [ "$a" -lt "$b" ]; then
echo 'a is less than b'
fia is less than bCompare a variable to a literal the same way:
count=3
if [ "$count" -eq 3 ]; then
echo 'count is exactly three'
ficount is exactly threeCompare Numbers with [[ ]]
[[ … ]] is Bash conditional syntax. The same numeric operators (-eq, -lt, -gt, and others) are available inside [[ … ]]:
a=5
b=10
if [[ "$a" -lt "$b" ]]; then
echo 'a is less than b'
fia is less than bInside [[ … ]], < and > compare strings in collation order — not as integers. Use -lt and -gt for numeric relations:
[[ 9 -lt 10 ]] && echo 'numeric nine is less than ten'numeric nine is less than tenA lexicographic check shows why string rules differ — 9 is not less than 10 as text:
[[ 9 < 10 ]] && echo 'string match' || echo 'string compare did not say 9 < 10'string compare did not say 9 < 10Compare Numbers with (( ))
Inside (( … )), Bash treats the expression as integer arithmetic. Use C-style operators (<, >, ==, !=, <=, >=) and omit $ on simple variable names:
a=5
b=10
if (( a < b )); then
echo 'a is less than b'
fia is less than bIn Bash-only scripts, (( … )) is often the clearest form when the condition is purely arithmetic. (( expression )) returns status 0 when the expression evaluates to a nonzero value, and status 1 when it evaluates to zero — which is how Bash if, elif, else and loops branch on it.
Compare Numbers for Equality
Numeric equality in bracket form:
a=10
b=10
if [ "$a" -eq "$b" ]; then
echo 'equal'
fiequalArithmetic equality in (( )):
if (( a == b )); then
echo 'equal'
fiequalUse -eq / -ne in [ … ] and [[ … ]]. Use == / != inside (( … )).
Greater Than and Less Than Examples
Threshold checks appear often in scripts. Disk usage at or above a limit:
used=87
threshold=85
if [ "$used" -ge "$threshold" ]; then
echo "disk usage at or above ${threshold}%"
fidisk usage at or above 85%Retry while attempts stay below a maximum:
attempts=3
max=5
if [ "$attempts" -lt "$max" ]; then
echo 'retry allowed'
firetry allowedNumeric conditions also work in loops — for example while (( a < 3 )); do … — see Bash while loop for loop syntax.
Empty, Invalid and Negative Input
If your application intentionally treats an empty value as zero, assign a default with parameter expansion before comparing — Bash variables covers ${n:-0} and quoting rules:
n=''
n=${n:-0}
if [ "$n" -eq 0 ]; then
echo 'empty defaults to zero'
fiempty defaults to zeroNon-numeric text passed to [ ] fails:
bash -c 'n=abc; [ "$n" -gt 0 ]' 2>&1 || truebash: line 1: [: abc: integer expression expectedThe behavior differs in arithmetic contexts. Inside [[ … -gt … ]] and (( … )), Bash evaluates operands as arithmetic expressions, so text such as abc may be interpreted as a variable name rather than rejected as invalid numeric input:
bash -c 'n=abc; abc=5; [[ $n -gt 0 ]] && echo "[[ treats abc as variable name"'[[ treats abc as variable nameThe same arithmetic-variable interpretation applies in (( )). That is why validation of external input matters before any numeric condition.
Validate external or user input before numeric comparison. Bash regex explains =~ and anchoring; here the pattern ^-?[0-9]+$ accepts an optional leading minus sign followed by one or more digits. Do not quote the regex on the right side of =~.
input='abc'
if [[ "$input" =~ ^-?[0-9]+$ ]]; then
echo 'valid integer input'
else
echo 'invalid integer input'
fiinvalid integer inputThis regex validates a signed decimal digit string; it does not normalize leading zeros for Bash arithmetic. A value such as 08 passes this syntax check but still needs the leading-zero handling described below:
input=08
if [[ "$input" =~ ^-?[0-9]+$ ]]; then
echo 'valid integer input'
fivalid integer inputThis check validates the input format, not whether the value fits within Bash's fixed-width integer range.
Negative integers work in (( )):
n=-3
if (( n < 0 )); then
echo 'negative'
finegativeLeading Zeros and 10#
Leading-zero behavior differs by comparison form — see Bash test vs double brackets for how [ ], [[ ]], and (( )) parse operands. [[ $a -eq $b ]] looks like a bracket comparison, but Bash evaluates its operands using shell-arithmetic rules. That is why leading-zero values can trigger octal parsing there. In [[ … -eq … ]] and (( … )), a leading 0 indicates octal notation, so 08 is invalid. The traditional [ … ] / test form follows different integer parsing rules.
[[ … ]] errors on 08:
bash -c 'a=08; b=8; [[ $a -eq $b ]]' 2>&1 || truebash: line 1: [[: 08: value too great for base (error token is "08")With Bash's [ … ] builtin, 08 and 8 compare successfully in this example — [ … ] does not apply the same arithmetic-base rules as [[ … ]]:
a=08
b=8
[ "$a" -eq "$b" ] && echo '[ ] eq works'[ ] eq worksForce decimal interpretation with 10# in arithmetic for non-negative digit strings:
a=08
if (( 10#$a == 8 )); then
echo '10# treats 08 as decimal 8'
fi10# treats 08 as decimal 8Normalize zero-padded decimal input before arithmetic, or use 10# after validation. Use 10#$var only after confirming that var contains a non-negative digit string. For signed zero-padded input, remove and remember the leading -, apply 10# to the digit portion, then restore the sign — 10#-08 is not valid Bash arithmetic syntax.
Compare Decimal / Floating-Point Values
-eq, -gt, and (( )) handle integers only. For decimals, use bc or awk — see Bash arithmetic for broader calculation patterns. These examples assume a and b already contain valid decimal numbers. Validate externally supplied values before building a bc expression or passing them to a numeric comparison.
With bc
bc prints 1 for a true comparison and 0 for a false one. Bash can use that result inside (( … )):
a=3.14
b=2.71
if (( $(bc <<< "$a > $b") )); then
echo 'a greater than b'
fia greater than bWith awk
Pass the values as variables and let awk exit with status 0 when the comparison is true:
a=3.14
b=2.71
if awk -v a="$a" -v b="$b" 'BEGIN { exit !(a > b) }'; then
echo 'a greater than b'
fia greater than bawk exits with status 0 when the comparison is true, so Bash can use it directly in if.
Common Numeric Comparison Mistakes
| Problem | Cause | Fix |
|---|---|---|
value too great for base on 08 |
Octal parsing in [[ … ]] / (( )) |
Normalize zero-padded input, or use 10# after validation |
9 not less than 10 in [[ ]] |
Used < instead of -lt |
-lt / -gt for integers; < / > compare strings in [[ ]] |
unary operator expected in [ ] |
Unquoted empty value disappeared from the test | Quote numeric operands |
too many arguments in [ ] |
Unquoted value split into multiple words | Quote expansions or validate input |
integer expression expected |
Non-numeric string in [ … ] |
Validate input before comparing |
3.14 fails in -eq or (( )) |
Bash integer arithmetic only | Compare decimals with bc or awk |
Used = for numeric equality |
= compares strings in [ … ] |
Use -eq / -ne for integers |
< or > behaves like redirection with [ ] |
The shell parses bare < and > as redirection operators |
Use -lt / -gt, or use [[ ]] / (( )) |
Inside [ … ], never use bare < or > for numeric relations — the shell parses them as redirection operators.
Summary
Pick [ "$a" -gt "$b" ] when you need POSIX portability, [[ "$a" -gt "$b" ]] for Bash integer tests in one conditional block, and (( a > b )) when the condition is purely arithmetic. Quote operands in [ … ]; use -eq, -lt, and -gt for integers in bracket forms — not < or > in [[ ]] for numeric order.
Leading-zero handling differs: [[ … ]] and (( )) parse 08 as octal because their operands follow shell-arithmetic rules, while Bash's [ … ] follows different integer parsing rules. Normalize zero-padded input or use 10#$var after validation, check untrusted input before comparing, and reach for bc or awk when the values are decimal.
References
- GNU Bash manual — Bash Conditional Expressions
- GNU Bash manual — Shell Arithmetic
- GNU Bash manual — Conditional Constructs
- POSIX
testutility
Frequently Asked Questions
-gt vs > — which should I use?
Use -gt, -lt, -ge, and -le inside [ … ] and [[ … ]] for integer relations. Use > and < inside (( … )) for arithmetic. In [[ … ]], bare < and > compare strings, not numbers.
-eq vs == — which should I use?
Use -eq and -ne inside [ … ] and [[ … ]] for numeric equality. = and == compare strings there. Inside (( … )), use == and != for arithmetic equality.
Can Bash compare decimals?
Not with -eq or (( )) alone — those forms are integer-only. Compare floating-point values with bc, awk, or another tool that handles decimals.
Why does 08 fail?
In [[ … ]] and (( )), a leading 0 makes Bash treat the value as octal. 08 is not valid octal, so those forms can error. Bash's [ … ] follows different integer parsing rules. Use 10#$var only on validated non-negative digit strings, or strip the leading zero.
Do I need $ inside (( ))?
Not for simple variable names — (( a > b )) is enough. Use $ when you need parameter expansion, such as (( ${n:-0} > 5 )).

