Guide
Bash-Scripting
Beginner
Operators
Arithmetic, comparison, logical, and file test operators in Bash — and the crucial difference between [ ], [[ ]], and (( )).
Arithmetic Operators
A=10
B=3
echo $((A + B)) # 13
echo $((A - B)) # 7
echo $((A * B)) # 30
echo $((A / B)) # 3 — integer division, no decimals!
echo $((A % B)) # 1 — modulo (remainder)
echo $((A ** 2)) # 100 — exponentiation
((A++)) # increment A in place
((A += 5)) # A = A + 5
For non-integer math, Bash has no native support — use bc or awk:
echo "10 / 3" | bc -l # 3.33333333333333333333
awk "BEGIN {print 10/3}" # 3.33333
Comparison Operators
# Numeric comparisons — use inside (( )) or [ ]/[[ ]] with these operators:
[ "$A" -eq "$B" ] # equal
[ "$A" -ne "$B" ] # not equal
[ "$A" -gt "$B" ] # greater than
[ "$A" -lt "$B" ] # less than
[ "$A" -ge "$B" ] # greater or equal
[ "$A" -le "$B" ] # less or equal
((A > B)) # arithmetic context — use regular >, <, ==, != instead
# String comparisons — DIFFERENT operators than numeric!
[ "$STR1" = "$STR2" ] # equal
[ "$STR1" != "$STR2" ] # not equal
[[ "$STR1" > "$STR2" ]] # lexical greater-than (needs [[ ]], not [ ])
Classic trap: using -eq on strings or = on numbers gives wrong or confusing results — the operator families are not interchangeable.
Logical Operators
if [ "$A" -gt 5 ] && [ "$B" -lt 10 ]; then echo "both true"; fi
if [[ $A -gt 5 && $B -lt 10 ]]; then echo "both true, inside [[ ]]"; fi
if [ "$A" -gt 5 ] || [ "$B" -gt 5 ]; then echo "at least one true"; fi
if ! [ "$A" -eq "$B" ]; then echo "not equal"; fi
# Short-circuit command chaining (not just inside test brackets)
mkdir -p /tmp/app && cd /tmp/app # run cd ONLY if mkdir succeeded
grep -q "error" log.txt || echo "no errors found" # run echo ONLY if grep found NOTHING
File Test Operators
[ -f "$FILE" ] # is a regular file
[ -d "$DIR" ] # is a directory
[ -e "$PATH" ] # exists (any type)
[ -r "$FILE" ] # is readable
[ -w "$FILE" ] # is writable
[ -x "$FILE" ] # is executable
[ -s "$FILE" ] # exists AND is non-empty
[ -L "$FILE" ] # is a symbolic link
if [ ! -f "$CONFIG_FILE" ]; then
echo "Config file missing: $CONFIG_FILE" >&2
exit 1
fi
[ ] vs [[ ]] vs (( ))
| Construct | Purpose | Notes |
|---|---|---|
[ ] | POSIX test command | Portable to /bin/sh; requires careful quoting |
[[ ]] | Bash extended test | Supports &&, ` |
(( )) | Arithmetic evaluation | For numeric comparisons/math; no quoting needed inside |
[[ "$STR" =~ ^[0-9]+$ ]] # regex match — only works inside [[ ]]
(( A > B && C < D )) # cleaner arithmetic logic than [ ] with -gt/-lt
Production Considerations
- In portable scripts targeting
/bin/sh(many CI systems, Alpine’s default shell), you’re restricted to[ ]—[[ ]]and(( ))are bash-only extensions. - Always quote variables inside
[ ]([ "$VAR" = "x" ]) — an unquoted, empty variable breaks the test’s argument count and throws a syntax error. - Prefer
[[ ]]in bash-only scripts for its safety (no word-splitting on unquoted variables) and extra features like regex matching.
Quick Interview Answer
“Bash arithmetic uses
$(( ))or(( )); numeric string comparisons in[ ]use-eq/-gt/-lt, while string equality uses=/!=— mixing these up is a classic bug.[[ ]]is the safer, bash-only extended test supporting regex and pattern matching without needing to quote every variable, while[ ]is the portable POSIX equivalent needed for/bin/shscripts.”
Common Mistakes
- Using
-eqto compare strings, or=to compare numbers. - Forgetting to quote variables inside
[ ], causing “unary operator expected” errors on empty values. - Assuming
[[ ]]works in a script shebanged#!/bin/sh— it doesn’t;dashand other POSIX shells will error on it.
Add More Questions to This Guide
Know a question that should be here? Share it and help the community!
Open Google Form