Compare Numbers in Bash

Tested on RHEL 10.2 (Coughlan)
Package bash 5.2.26-6.el10
bc 1.08.2-5.el10
gawk 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
Short on time?Beta Get the gist of this 10-minute read in seconds, then ask follow-up questions

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:

bash
a=5
b=10

if [ "$a" -lt "$b" ]; then
  echo 'a is less than b'
fi
output
a is less than b

Compare a variable to a literal the same way:

bash
count=3

if [ "$count" -eq 3 ]; then
  echo 'count is exactly three'
fi
output
count is exactly three

Compare Numbers with [[ ]]

[[ … ]] is Bash conditional syntax. The same numeric operators (-eq, -lt, -gt, and others) are available inside [[ … ]]:

bash
a=5
b=10

if [[ "$a" -lt "$b" ]]; then
  echo 'a is less than b'
fi
output
a is less than b

Inside [[ … ]], < and > compare strings in collation order — not as integers. Use -lt and -gt for numeric relations:

bash
[[ 9 -lt 10 ]] && echo 'numeric nine is less than ten'
output
numeric nine is less than ten

A lexicographic check shows why string rules differ — 9 is not less than 10 as text:

bash
[[ 9 < 10 ]] && echo 'string match' || echo 'string compare did not say 9 < 10'
output
string compare did not say 9 < 10

Compare Numbers with (( ))

Inside (( … )), Bash treats the expression as integer arithmetic. Use C-style operators (<, >, ==, !=, <=, >=) and omit $ on simple variable names:

bash
a=5
b=10

if (( a < b )); then
  echo 'a is less than b'
fi
output
a is less than b

In 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:

bash
a=10
b=10

if [ "$a" -eq "$b" ]; then
  echo 'equal'
fi
output
equal

Arithmetic equality in (( )):

bash
if (( a == b )); then
  echo 'equal'
fi
output
equal

Use -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:

bash
used=87
threshold=85

if [ "$used" -ge "$threshold" ]; then
  echo "disk usage at or above ${threshold}%"
fi
output
disk usage at or above 85%

Retry while attempts stay below a maximum:

bash
attempts=3
max=5

if [ "$attempts" -lt "$max" ]; then
  echo 'retry allowed'
fi
output
retry allowed

Numeric 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:

bash
n=''
n=${n:-0}

if [ "$n" -eq 0 ]; then
  echo 'empty defaults to zero'
fi
output
empty defaults to zero

Non-numeric text passed to [ ] fails:

bash
bash -c 'n=abc; [ "$n" -gt 0 ]' 2>&1 || true
output
bash: line 1: [: abc: integer expression expected

The 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
bash -c 'n=abc; abc=5; [[ $n -gt 0 ]] && echo "[[ treats abc as variable name"'
output
[[ treats abc as variable name

The 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 =~.

bash
input='abc'

if [[ "$input" =~ ^-?[0-9]+$ ]]; then
  echo 'valid integer input'
else
  echo 'invalid integer input'
fi
output
invalid integer input

This 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:

bash
input=08

if [[ "$input" =~ ^-?[0-9]+$ ]]; then
  echo 'valid integer input'
fi
output
valid integer input

This check validates the input format, not whether the value fits within Bash's fixed-width integer range.

Negative integers work in (( )):

bash
n=-3

if (( n < 0 )); then
  echo 'negative'
fi
output
negative

Leading 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
bash -c 'a=08; b=8; [[ $a -eq $b ]]' 2>&1 || true
output
bash: 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 [[ … ]]:

bash
a=08
b=8
[ "$a" -eq "$b" ] && echo '[ ] eq works'
output
[ ] eq works

Force decimal interpretation with 10# in arithmetic for non-negative digit strings:

bash
a=08

if (( 10#$a == 8 )); then
  echo '10# treats 08 as decimal 8'
fi
output
10# treats 08 as decimal 8

Normalize 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 (( … )):

bash
a=3.14
b=2.71

if (( $(bc <<< "$a > $b") )); then
  echo 'a greater than b'
fi
output
a greater than b

With awk

Pass the values as variables and let awk exit with status 0 when the comparison is true:

bash
a=3.14
b=2.71

if awk -v a="$a" -v b="$b" 'BEGIN { exit !(a > b) }'; then
  echo 'a greater than b'
fi
output
a greater than b

awk 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


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 )).

Finished reading?Beta Get the key takeaways in seconds, then ask follow-up questions
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with 15+ years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)