Linux CLI 61 ๐ง modern test version and in (( )) shell scripts
#!/bin/bash
var1="test"
var2="test case"
if [[ $var1 = test ]]; then
echo "Using [[ ]], var1 is 'test'"
fi
if [[ "$var1" == "test" ]]; then
echo "Using [[ ]], var1 is 'test' with quotes"
fi
if [[ $var2 =~ test.* ]]; then
echo "Using [[ ]], var2 matches regex 'test.*'"
fi
if [[ 10 -eq 10 ]]; then
echo "Using [[ ]], 10 is equal to 10"
fi
a=5
b=3
sum=$((a + b))
difference=$((a - b))
product=$((a * b))
quotient=$((a / b))
remainder=$((a % b))
echo "Sum: $sum"
echo "Difference: $difference"
echo "Product: $product"
echo "Quotient: $quotient"
echo "Remainder: $remainder"
num1=20
num2=5
result=$((num1 + num2 * 3))
echo "Result: $result"
counter=0
counter=$((counter + 1))
echo "Counter after increment: $counter"
counter=$((counter - 1))
echo "Counter after decrement: $counter"
base=2
exponent=3
result=$((base ** exponent))
echo "$base raised to the power of $exponent is $result"
The older [ ] test has been around since the earliest days of Unix. [[ ]] is bash’s modern replacement โ it fixes the quoting headaches, adds regex and pattern matching, and generally makes conditions safer to write. And (( )) is its arithmetic counterpart โ a cleaner way to do integer math than expr or let.
Key point: [[ ]] is bash-specific (also ksh and zsh). It’s not POSIX โ so if your script must run under dash or plain sh, stick with [ ]. But for modern bash scripts, [[ ]] is almost always the better choice.
a – extended test command in shell scripts
Unlike the traditional [ ] (or test), which requires spaces around operators, [[ ]] does not have this requirement. It’s generally recommended to use [[ ]] over [ ] for most modern shell scripting needs due to its enhanced functionality and error prevention.
The key differences:
| Feature | [ ] | [[ ]] |
|---|---|---|
| POSIX | โ | โ (bash/ksh/zsh) |
| Word splitting | Yes | No |
| Pathname expansion | Yes | No |
| Quote variables | Required | Optional |
&& / || inside | No | Yes |
Regex =~ | No | Yes |
Pattern matching == | No | Yes |
< / > | Escape needed | Bare works |
| Parentheses grouping | No | Yes |
String comparison without quotes:
Without quotes, [ $var1 = test ] will fail if var1 is empty or contains spaces:
$ var1=""
$ [ $var1 = test ]
bash: [: =: unary operator expected
But [[ $var1 = test ]] handles it cleanly:
$ var1=""
$ [[ $var1 = test ]]
$ echo $?
[ 1 ]
The reason: [[ ]] doesn’t perform word splitting, so an empty variable is treated as an empty string โ not as “nothing at all.”
$ var1="test"
$ if [[ $var1 = test ]]; then echo "match"; fi
[ match ]
$ if [[ "$var1" == "test" ]]; then echo "match quoted"; fi
[ match quoted ]
Both work. The quotes are optional in [[ ]] โ but harmless and sometimes clearer.
Pattern matching:
[[ ]] supports glob patterns with ==:
$ file="report.txt"
$ if [[ $file == *.txt ]]; then echo "text file"; fi
[ text file ]
$ name="Alice"
$ if [[ $name == A* ]]; then echo "starts with A"; fi
[ starts with A ]
$ if [[ $name == *ice ]]; then echo "ends with ice"; fi
[ ends with ice ]
With [ ], this would expand the glob against the filesystem โ not what you want.
# โ In [ ], * is expanded by the shell before the test runs
[ "$file" = *.txt ] # fragile
# โ
In [[ ]], * is a pattern
[[ $file == *.txt ]] # reliable
Regex matching with =~:
$ var2="test case"
$ if [[ $var2 =~ test.* ]]; then echo "matches regex"; fi
[ matches regex ]
$ email="user@example.com"
$ if [[ $email =~ ^[a-z]+@[a-z]+\.[a-z]{2,}$ ]]; then echo "valid"; fi
[ valid ]
$ phone="555-1234"
$ if [[ $phone =~ ^[0-9]{3}-[0-9]{4}$ ]]; then echo "valid phone"; fi
[ valid phone ]
The regex is not quoted โ quoting it would make it a literal string. To match a literal, put the pattern in a variable:
$ pattern="test.*"
$ if [[ $var2 =~ $pattern ]]; then echo "match"; fi
[ match ]
Numeric comparisons:
Both [ ] and [[ ]] support numeric comparisons the same way:
$ if [[ 10 -eq 10 ]]; then echo "equal"; fi
[ equal ]
$ a=5
$ b=10
$ if [[ $a -lt $b ]]; then echo "less"; fi
[ less ]
Combining conditions inside [[ ]]:
This is one of the biggest wins โ && and || work inside the brackets:
$ a=5
$ b=10
$ if [[ $a -gt 0 && $b -gt 0 ]]; then echo "both positive"; fi
[ both positive ]
$ if [[ $a -gt 100 || $b -gt 5 ]]; then echo "at least one"; fi
[ at least one ]
$ if [[ ! -f /nonexistent ]]; then echo "not a file"; fi
[ not a file ]
With [ ], you need separate brackets:
if [ $a -gt 0 ] && [ $b -gt 0 ]; then ...; fi
Grouping with parentheses:
$ if [[ ($a -gt 0 && $b -gt 0) || $a -eq 100 ]]; then
> echo "condition met"
> fi
[ condition met ]
< and > without escaping:
In [ ], < and > are redirection operators โ you have to escape them:
# โ Creates a file called "b"
[ "$a" > "$b" ]
# โ
Escaped
[ "$a" \> "$b" ]
In [[ ]], they work bare:
$ a="apple"
$ b="banana"
$ if [[ $a < $b ]]; then echo "a comes first"; fi
[ a comes first ]
File tests work the same:
$ if [[ -f /etc/passwd ]]; then echo "file"; fi
[ file ]
$ if [[ -d /etc ]]; then echo "dir"; fi
[ dir ]
$ if [[ -x /usr/bin/ls ]]; then echo "exec"; fi
[ exec ]
When to use [[ ]] vs [ ]:
Use [[ ]] when | Use [ ] when |
|---|---|
| Writing bash scripts | Need POSIX portability |
| You want regex matching | Running under sh or dash |
| You want glob patterns | Writing portable scripts |
You want && / ` | |
| You don’t want to quote | |
| You want safer conditions |
Rule of thumb: Default to
[[ ]]in modern bash. Only fall back to[ ]if you need portability.
b – (( )) in shell scripts
(( )) is used for arithmetic evaluation. It allows you to perform mathematical operations and handle integer arithmetic directly within your scripts.
Syntax:
result=$((expression))
expression can include any valid arithmetic operation involving integers:
| Operator | Meaning |
|---|---|
+ | Addition |
- | Subtraction |
* | Multiplication |
/ | Division |
% | Modulus (remainder) |
** | Exponentiation |
++ | Increment |
-- | Decrement |
+=, -=, *=, /= | Compound assignment |
Key points:
- Integer arithmetic only โ
(( ))supports only integer math. For floating point, usebcorawk. - Expression evaluation โ the entire expression is evaluated to a single integer value.
- Precedence and associativity โ standard math rules apply: multiplication and division before addition and subtraction. Parentheses can change the order.
Example 1 โ Simple arithmetic operations:
a=5
b=3
sum=$((a + b))
difference=$((a - b))
product=$((a * b))
quotient=$((a / b))
remainder=$((a % b))
echo "Sum: $sum"
echo "Difference: $difference"
echo "Product: $product"
echo "Quotient: $quotient"
echo "Remainder: $remainder"
[ Sum: 8 ]
[ Difference: 2 ]
[ Product: 15 ]
[ Quotient: 1 ]
[ Remainder: 2 ]
Note:
5 / 3is1โ integer division truncates.5 % 3is2โ the remainder.
Example 2 โ Using variables and expressions:
num1=20
num2=5
result=$((num1 + num2 * 3))
echo "Result: $result"
[ Result: 35 ]
The multiplication happens first (5 * 3 = 15), then the addition (20 + 15 = 35). To change the order, use parentheses:
$ result=$(( (num1 + num2) * 3 ))
$ echo "Result: $result"
[ Result: 75 ]
Example 3 โ Incrementing and decrementing variables:
counter=0
counter=$((counter + 1))
echo "Counter after increment: $counter"
[ Counter after increment: 1 ]
counter=$((counter - 1))
echo "Counter after decrement: $counter"
[ Counter after decrement: 0 ]
The shorter form:
$ counter=0
$ ((counter++))
$ echo $counter
[ 1 ]
$ ((counter--))
$ echo $counter
[ 0 ]
Or with compound assignment:
$ counter=10
$ ((counter += 5))
$ echo $counter
[ 15 ]
$ ((counter -= 3))
$ echo $counter
[ 12 ]
$ ((counter *= 2))
$ echo $counter
[ 24 ]
$ ((counter /= 4))
$ echo $counter
[ 6 ]
Example 4 โ Using exponentiation:
base=2
exponent=3
result=$((base ** exponent))
echo "$base raised to the power of $exponent is $result"
[ 2 raised to the power of 3 is 8 ]
Comparing (( )) forms:
There are three ways to use arithmetic in bash:
| Form | Purpose | Example |
|---|---|---|
$((...)) | Produce a value | x=$((a + b)) |
((...)) | Evaluate, set exit status | ((a > b)) |
let | Older alternative | let x=a+b |
$((...)) vs ((...)):
$((...))produces output โ you capture it or print it((...))sets an exit status โ useful inif
# $(( )) produces a value
$ x=$((5 + 3))
$ echo $x
[ 8 ]
# (( )) sets an exit status
$ ((5 > 3))
$ echo $?
[ 0 ]
$ ((5 < 3))
$ echo $?
[ 1 ]
Using (( )) in conditions:
$ a=5
$ b=10
$ if ((a < b)); then echo "a is less"; fi
[ a is less ]
$ if ((a == 5 && b == 10)); then echo "both match"; fi
[ both match ]
$ if ((a > 0)); then echo "positive"; fi
[ positive ]
This is cleaner than [[ $a -lt $b ]] โ you write the comparison the way you’d write it in C.
(( )) vs [[ ]] for arithmetic:
# With [[ ]] โ bash test operators
if [[ $a -lt $b ]]; then ...; fi
# With (( )) โ C-style operators
if ((a < b)); then ...; fi
Both work. (( )) is more natural for math-heavy conditions.
Floating-point limitation:
(( )) only handles integers. For decimals, use bc or awk:
# โ Wrong โ bash arithmetic is integer only
$ result=$((10 / 3))
$ echo $result
[ 3 ]
# โ
With bc
$ result=$(echo "scale=2; 10 / 3" | bc)
$ echo $result
[ 3.33 ]
# โ
With awk
$ result=$(awk 'BEGIN {print 10 / 3}')
$ echo $result
[ 3.33333 ]
Common uses of (( )):
# Counters in loops
$ for ((i=1; i<=5; i++)); do echo "$i"; done
[ 1 ]
[ 2 ]
[ 3 ]
[ 4 ]
[ 5 ]
# Conditional arithmetic
$ ((count++))
$ ((total += amount))
# Generate a random number
$ echo $((RANDOM % 100))
[ 42 ]
# Index an array
$ arr=(a b c d)
$ i=2
$ echo "${arr[$i]}"
[ c ]
C-style for loop:
#!/bin/bash
for ((i=1; i<=5; i++)); do
echo "Iteration $i"
done
[ Iteration 1 ]
[ Iteration 2 ]
[ Iteration 3 ]
[ Iteration 4 ]
[ Iteration 5 ]
Arithmetic assignment operators:
$ x=10
$ ((x += 5)); echo $x # 15
$ ((x -= 3)); echo $x # 12
$ ((x *= 2)); echo $x # 24
$ ((x /= 4)); echo $x # 6
$ ((x %= 4)); echo $x # 2
$ ((x **= 3)); echo $x # 8
Bitwise operators (bonus):
| Operator | Meaning |
|---|---|
& | AND |
| | OR |
^ | XOR |
~ | NOT |
<< | Left shift |
>> | Right shift |
$ echo $((5 & 3))
[ 1 ]
$ echo $((5 | 3))
[ 7 ]
$ echo $((5 ^ 3))
[ 6 ]
$ echo $((1 << 4))
[ 16 ]
$ echo $((16 >> 2))
[ 4 ]
Comparison: $(( )) vs expr vs let:
| Method | Example | Notes |
|---|---|---|
$(( )) | x=$((a+b)) | Modern, preferred |
(( )) | ((a++)) | For side effects |
let | let x=a+b | Older, still works |
expr | x=$(expr $a + $b) | Obsolete, avoid |
bc | echo "a+b" | bc | For floating point |
Rule of thumb: Use
$(( ))for producing values,(( ))for conditions and side effects. Never useexprin new scripts.
Complete Example Session
# ============================================
# PART 1: [[ ]] WITH STRING COMPARISON
# ============================================
$ var1="test"
$ var2="test case"
$ if [[ $var1 = test ]]; then echo "match"; fi
[ match ]
$ if [[ "$var1" == "test" ]]; then echo "match quoted"; fi
[ match quoted ]
$ if [[ $var1 != other ]]; then echo "not other"; fi
[ not other ]
# ============================================
# PART 2: [[ ]] WITH REGEX
# ============================================
$ if [[ $var2 =~ test.* ]]; then echo "matches regex"; fi
[ matches regex ]
$ email="user@example.com"
$ if [[ $email =~ ^[a-z]+@[a-z]+\.[a-z]{2,}$ ]]; then echo "valid"; fi
[ valid ]
# ============================================
# PART 3: [[ ]] WITH GLOB PATTERNS
# ============================================
$ file="report.txt"
$ if [[ $file == *.txt ]]; then echo "text"; fi
[ text ]
$ name="Alice"
$ if [[ $name == A* ]]; then echo "starts with A"; fi
[ starts with A ]
# ============================================
# PART 4: [[ ]] WITH NUMBERS
# ============================================
$ if [[ 10 -eq 10 ]]; then echo "equal"; fi
[ equal ]
$ a=5
$ b=10
$ if [[ $a -lt $b ]]; then echo "less"; fi
[ less ]
# ============================================
# PART 5: [[ ]] WITH COMBINED CONDITIONS
# ============================================
$ a=5
$ b=10
$ if [[ $a -gt 0 && $b -gt 0 ]]; then echo "both positive"; fi
[ both positive ]
$ if [[ $a -gt 100 || $b -gt 5 ]]; then echo "at least one"; fi
[ at least one ]
$ if [[ ! -f /nonexistent ]]; then echo "not a file"; fi
[ not a file ]
# ============================================
# PART 6: [[ ]] WITH GROUPING
# ============================================
$ if [[ ($a -gt 0 && $b -gt 0) || $a -eq 100 ]]; then
> echo "condition met"
> fi
[ condition met ]
# ============================================
# PART 7: [[ ]] WITH < AND >
# ============================================
$ a="apple"
$ b="banana"
$ if [[ $a < $b ]]; then echo "a first"; fi
[ a first ]
# ============================================
# PART 8: SIMPLE ARITHMETIC WITH $(( ))
# ============================================
$ a=5
$ b=3
$ echo $((a + b))
[ 8 ]
$ echo $((a - b))
[ 2 ]
$ echo $((a * b))
[ 15 ]
$ echo $((a / b))
[ 1 ]
$ echo $((a % b))
[ 2 ]
# ============================================
# PART 9: PRECEDENCE
# ============================================
$ num1=20
$ num2=5
$ echo $((num1 + num2 * 3))
[ 35 ]
$ echo $(((num1 + num2) * 3))
[ 75 ]
# ============================================
# PART 10: INCREMENT / DECREMENT
# ============================================
$ counter=0
$ ((counter++))
$ echo $counter
[ 1 ]
$ ((counter--))
$ echo $counter
[ 0 ]
# ============================================
# PART 11: COMPOUND ASSIGNMENT
# ============================================
$ x=10
$ ((x += 5)); echo $x
[ 15 ]
$ ((x -= 3)); echo $x
[ 12 ]
$ ((x *= 2)); echo $x
[ 24 ]
$ ((x /= 4)); echo $x
[ 6 ]
# ============================================
# PART 12: EXPONENTIATION
# ============================================
$ base=2
$ exponent=3
$ echo $((base ** exponent))
[ 8 ]
# ============================================
# PART 13: ARITHMETIC IN CONDITIONS
# ============================================
$ a=5
$ b=10
$ if ((a < b)); then echo "less"; fi
[ less ]
$ if ((a == 5 && b == 10)); then echo "both"; fi
[ both ]
# ============================================
# PART 14: C-STYLE FOR LOOP
# ============================================
$ for ((i=1; i<=5; i++)); do echo "$i"; done
[ 1 ]
[ 2 ]
[ 3 ]
[ 4 ]
[ 5 ]
# ============================================
# PART 15: RANDOM NUMBER
# ============================================
$ echo $((RANDOM % 100))
[ 42 ]
# ============================================
# PART 16: INTEGER DIVISION TRUNCATION
# ============================================
$ echo $((10 / 3))
[ 3 ]
# Float requires bc
$ echo "scale=2; 10 / 3" | bc
[ 3.33 ]
# Or awk
$ awk 'BEGIN {print 10 / 3}'
[ 3.33333 ]
# ============================================
# PART 17: BITWISE OPERATORS
# ============================================
$ echo $((5 & 3))
[ 1 ]
$ echo $((5 | 3))
[ 7 ]
$ echo $((5 ^ 3))
[ 6 ]
$ echo $((1 << 4))
[ 16 ]
# ============================================
# PART 18: FULL SCRIPT
# ============================================
$ cat > modern.sh << 'EOF'
#!/bin/bash
var1="test"
var2="test case"
if [[ $var1 = test ]]; then
echo "Using [[ ]], var1 is 'test'"
fi
if [[ "$var1" == "test" ]]; then
echo "Using [[ ]], var1 is 'test' with quotes"
fi
if [[ $var2 =~ test.* ]]; then
echo "Using [[ ]], var2 matches regex 'test.*'"
fi
if [[ 10 -eq 10 ]]; then
echo "Using [[ ]], 10 is equal to 10"
fi
a=5
b=3
sum=$((a + b))
difference=$((a - b))
product=$((a * b))
quotient=$((a / b))
remainder=$((a % b))
echo "Sum: $sum"
echo "Difference: $difference"
echo "Product: $product"
echo "Quotient: $quotient"
echo "Remainder: $remainder"
num1=20
num2=5
result=$((num1 + num2 * 3))
echo "Result: $result"
counter=0
counter=$((counter + 1))
echo "Counter after increment: $counter"
counter=$((counter - 1))
echo "Counter after decrement: $counter"
base=2
exponent=3
result=$((base ** exponent))
echo "$base raised to the power of $exponent is $result"
EOF
$ chmod +x modern.sh
$ ./modern.sh
[ Using [[ ]], var1 is 'test' ]
[ Using [[ ]], var1 is 'test' with quotes ]
[ Using [[ ]], var2 matches regex 'test.*' ]
[ Using [[ ]], 10 is equal to 10 ]
[ Sum: 8 ]
[ Difference: 2 ]
[ Product: 15 ]
[ Quotient: 1 ]
[ Remainder: 2 ]
[ Result: 35 ]
[ Counter after increment: 1 ]
[ Counter after decrement: 0 ]
[ 2 raised to the power of 3 is 8 ]
Quick Reference
[ ] vs [[ ]]
| Feature | [ ] | [[ ]] |
|---|---|---|
| POSIX | โ | โ |
| Quote required | Yes | No |
| Word splitting | Yes | No |
| Glob expansion | Yes | No |
&& inside | โ | โ |
|| inside | โ | โ |
Regex =~ | โ | โ |
Glob == | โ | โ |
< / > | Escape | Bare |
Grouping () | โ | โ |
[[ ]] Operators
| Operator | Meaning |
|---|---|
= / == | String equality |
!= | String inequality |
=~ | Regex match |
-eqโ-ge | Numeric comparisons |
-fโ-x | File tests |
&& | AND |
|| | OR |
! | NOT |
( ) | Grouping |
(( )) Arithmetic
| Operator | Meaning |
|---|---|
+ | Addition |
- | Subtraction |
* | Multiplication |
/ | Integer division |
% | Modulus |
** | Exponentiation |
++ / -- | Increment / decrement |
+= -= *= /= | Compound assignment |
& | ^ ~ << >> | Bitwise |
Three Forms of Arithmetic
| Form | Purpose | Example |
|---|---|---|
$(( )) | Produce a value | x=$((a+b)) |
(( )) | Evaluate, set status | ((a > b)) |
let | Older alternative | let x=a+b |
(( )) in Conditions
| Expression | Meaning |
|---|---|
((a < b)) | a less than b |
((a <= b)) | a less or equal |
((a == b)) | a equal to b |
((a != b)) | a not equal |
((a && b)) | both non-zero |
((a || b)) | either non-zero |
((!a)) | a is zero |
Floating Point
| Tool | Example |
|---|---|
bc | echo "scale=2; 10/3" | bc |
awk | awk 'BEGIN {print 10/3}' |
Best Practices
โ Do This:
# Use [[ ]] in bash scripts
if [[ $var == "value" ]]; then ...; fi # โ
# Use regex for pattern matching
if [[ $email =~ ^[a-z]+@ ]]; then ...; fi # โ
# Use glob patterns with ==
if [[ $file == *.txt ]]; then ...; fi # โ
# Combine conditions inside [[ ]]
if [[ $a -gt 0 && $b -gt 0 ]]; then ...; fi # โ
# Use (( )) for arithmetic conditions
if ((a < b)); then ...; fi # โ
# Use $(( )) for values
sum=$((a + b)) # โ
# Use C-style for loops
for ((i=0; i<10; i++)); do ...; done # โ
# Use bc or awk for floats
result=$(echo "scale=2; 10/3" | bc) # โ
# Use compound assignment for clarity
((count += 1)) # โ
โ Don’t Do This:
# Don't use [[ ]] in sh scripts
#!/bin/sh
[[ $a == b ]] # โ not POSIX
# Don't quote the regex in [[ =~ ]]
if [[ $s =~ "test.*" ]]; then ...; fi # โ literal match
if [[ $s =~ test.* ]]; then ...; fi # โ
# Don't use -eq for strings
[[ "$name" -eq "Alice" ]] # โ error
[[ "$name" == "Alice" ]] # โ
# Don't use = for numbers in [[ ]]
[[ $a = 5 ]] # โ ๏ธ string compare
((a == 5)) # โ
# Don't expect floats from (( ))
echo $((10 / 3)) # โ gives 3
echo "scale=2; 10/3" | bc # โ
# Don't use expr in modern scripts
x=$(expr $a + $b) # โ obsolete
x=$((a + b)) # โ
# Don't forget spaces in (( )) when needed
((a=5)) # โ ๏ธ assignment
((a == 5)) # โ
comparison
Common Pitfalls
| Pitfall | Problem | Solution |
|---|---|---|
[[ ]] in sh | Not POSIX | Use [ ] or bash shebang |
| Quoted regex | Literal match | Don’t quote the pattern |
Floats in (( )) | Truncated | Use bc or awk |
= vs == in [[ ]] | Both work | Fine either way |
((a=5)) | Assignment, not compare | Use ((a == 5)) |
Missing $ in $(( )) | Variable names OK | $((a + b)) works |
(( )) with strings | Error | Use [[ ]] for strings |
Real-World Examples
1. String Comparison with [[ ]]
#!/bin/bash
var1="test"
if [[ $var1 = test ]]; then
echo "var1 is 'test'"
fi
[ var1 is 'test' ]
2. Quoted Comparison
#!/bin/bash
var1="test"
if [[ "$var1" == "test" ]]; then
echo "var1 is 'test' with quotes"
fi
[ var1 is 'test' with quotes ]
3. Regex Match
#!/bin/bash
var2="test case"
if [[ $var2 =~ test.* ]]; then
echo "var2 matches regex 'test.*'"
fi
[ var2 matches regex 'test.*' ]
4. Numeric Comparison
#!/bin/bash
if [[ 10 -eq 10 ]]; then
echo "10 is equal to 10"
fi
[ 10 is equal to 10 ]
5. Full Arithmetic
#!/bin/bash
a=5
b=3
echo "Sum: $((a + b))"
echo "Difference: $((a - b))"
echo "Product: $((a * b))"
echo "Quotient: $((a / b))"
echo "Remainder: $((a % b))"
[ Sum: 8 ]
[ Difference: 2 ]
[ Product: 15 ]
[ Quotient: 1 ]
[ Remainder: 2 ]
6. Operator Precedence
#!/bin/bash
num1=20
num2=5
result=$((num1 + num2 * 3))
echo "Result: $result"
[ Result: 35 ]
7. Increment / Decrement
#!/bin/bash
counter=0
counter=$((counter + 1))
echo "Counter: $counter"
counter=$((counter - 1))
echo "Counter: $counter"
[ Counter: 1 ]
[ Counter: 0 ]
8. Exponentiation
#!/bin/bash
base=2
exponent=3
result=$((base ** exponent))
echo "$base ^ $exponent = $result"
[ 2 ^ 3 = 8 ]
9. Email Validation
#!/bin/bash
read -p "Email: " email
if [[ $email =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$ ]]; then
echo "Valid"
else
echo "Invalid"
fi
10. File Extension Check
#!/bin/bash
file="$1"
if [[ $file == *.txt ]]; then
echo "Text file"
elif [[ $file == *.jpg || $file == *.png ]]; then
echo "Image file"
else
echo "Other"
fi
11. Numeric Range
#!/bin/bash
read -p "Score: " score
if ((score >= 90 && score <= 100)); then
echo "A"
elif ((score >= 80)); then
echo "B"
else
echo "C or below"
fi
12. Countdown
#!/bin/bash
for ((i=10; i>0; i--)); do
echo "$i"
sleep 0.1
done
echo "Liftoff!"
13. Random Number
#!/bin/bash
echo "Random: $((RANDOM % 100))"
[ Random: 42 ]
14. Accumulator
#!/bin/bash
total=0
for n in 1 2 3 4 5; do
((total += n))
done
echo "Total: $total"
[ Total: 15 ]
15. Bitwise Operations
#!/bin/bash
echo "AND: $((5 & 3))"
echo "OR: $((5 | 3))"
echo "XOR: $((5 ^ 3))"
echo "SHL: $((1 << 4))"
echo "SHR: $((16 >> 2))"
[ AND: 1 ]
[ OR: 7 ]
[ XOR: 6 ]
[ SHL: 16 ]
[ SHR: 4 ]
16. Float with bc
#!/bin/bash
a=10
b=3
result=$(echo "scale=2; $a / $b" | bc)
echo "$a / $b = $result"
[ 10 / 3 = 3.33 ]
17. Float with awk
#!/bin/bash
result=$(awk 'BEGIN {printf "%.2f", 10 / 3}')
echo "Result: $result"
[ Result: 3.33 ]
18. Power Table
#!/bin/bash
for i in 1 2 3 4 5; do
echo "2^$i = $((2 ** i))"
done
[ 2^1 = 2 ]
[ 2^2 = 4 ]
[ 2^3 = 8 ]
[ 2^4 = 16 ]
[ 2^5 = 32 ]
19. Modern vs Old Test
#!/bin/bash
# Old way
if [ "$1" = "start" ] && [ -n "$1" ]; then
echo "old style"
fi
# Modern way
if [[ $1 == "start" && -n $1 ]]; then
echo "modern style"
fi
20. Full Modern Script
#!/bin/bash
# String tests with [[ ]]
name="Alice"
if [[ $name == A* ]]; then
echo "Starts with A"
fi
if [[ $name =~ ^[A-Z] ]]; then
echo "Starts with capital"
fi
# Numeric tests with (( ))
age=30
if ((age >= 18)); then
echo "Adult"
fi
# Arithmetic
total=$((age * 2))
echo "Double age: $total"
# Counter loop
for ((i=1; i<=3; i++)); do
echo "Iteration $i"
done
[ Starts with A ]
[ Starts with capital ]
[ Adult ]
[ Double age: 60 ]
[ Iteration 1 ]
[ Iteration 2 ]
[ Iteration 3 ]
Visual: [ ] vs [[ ]]
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ [ ] โ old test โ
โ โ
โ if [ "$var" = "value" ]; then โ
โ # must quote โ
โ fi โ
โ โ
โ if [ -f file ] && [ -r file ]; then โ
โ # separate brackets โ
โ fi โ
โ โ
โ โข Word splitting โ
โ โข Glob expansion โ
โ โข No regex โ
โ โข POSIX โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ [[ ]] โ modern test โ
โ โ
โ if [[ $var == "value" ]]; then โ
โ # no quotes needed โ
โ fi โ
โ โ
โ if [[ -f file && -r file ]]; then โ
โ # combine inside โ
โ fi โ
โ โ
โ if [[ $email =~ @.*\.com$ ]]; then โ
โ # regex! โ
โ fi โ
โ โ
โ โข No word splitting โ
โ โข No glob expansion โ
โ โข Regex and globs โ
โ โข bash / ksh / zsh โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Visual: $(( )) vs (( ))
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ $(( )) โ produces a value โ
โ โ
โ sum=$((a + b)) โ
โ echo "Sum: $sum" โ
โ โ
โ The result is captured or printed. โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
โ (( )) โ sets exit status โ
โ โ
โ if ((a < b)); then โ
โ echo "a is less" โ
โ fi โ
โ โ
โ ((counter++)) โ
โ โ
โ Used for conditions and side effects. โ
โ โ
โโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโโ
Summary
| Concept | Syntax | Example |
|---|---|---|
| Modern test | [[ EXPR ]] | [[ $a == b ]] |
| String equality | == / = | [[ $name == Alice ]] |
| String inequality | != | [[ $a != $b ]] |
| Regex match | =~ | [[ $s =~ pat ]] |
| Glob pattern | == | [[ $f == *.txt ]] |
| Numeric compare | -eqโ-ge | [[ $a -lt $b ]] |
| File test | -fโ-x | [[ -f file ]] |
| AND | && | [[ $a && $b ]] |
| OR | || | [[ $a || $b ]] |
| NOT | ! | [[ ! -f f ]] |
| Grouping | ( ) | [[ (a || b) && c ]] |
| Arithmetic value | $(( )) | x=$((a+b)) |
| Arithmetic condition | (( )) | ((a < b)) |
| Increment | ++ | ((i++)) |
| Decrement | -- | ((i--)) |
| Compound assign | += -= *= /= | ((x += 5)) |
| Exponentiation | ** | $((2 ** 3)) |
| Bitwise | & | ^ ~ << >> | $((5 & 3)) |
| C-style for | for ((...)) | for ((i=0;i<5;i++)) |
| Float with bc | | bc | echo "10/3" | bc |
| Float with awk | awk | awk 'BEGIN{print 10/3}' |
Key takeaways:
[[ ]]is the modern bash test โ safer, more powerful, and easier to write than[ ]- No word splitting or glob expansion inside
[[ ]]โ variables don’t need quotes =~enables regex matching;==with a pattern enables glob matching&&and||work inside[[ ]]โ no need for multiple brackets<and>work bare โ no escaping needed[[ ]]is not POSIX โ forshordash, use[ ]$(( ))produces a value โ capture it or print it(( ))sets an exit status โ use it inifand for side effects- Arithmetic is integer-only โ use
bcorawkfor floats - Precedence is standard math โ use parentheses to change the order
++,--, and compound assignment make counters clean**is exponentiation โ bash-specific but very handy- C-style for loops (
for ((i=0;i<n;i++))) are clearer thanseqfor numeric ranges
Remember: In modern bash, reach for [[ ]] first. It’s safer and more capable than [ ], and it handles empty variables, globs, and regex gracefully. Use $(( )) when you want a value and (( )) when you want a condition. Know that arithmetic is integer-only, and reach for bc or awk when you need decimals. Master these two constructs, and your conditions and calculations become clean, correct, and idiomatic bash.
Stop using slow, ad-bloated tool sites! ๐คฎ
๐ Search “KandZ Tools” on Google to use many professional utilities for free.
KandZ.me is the ultimate minimalist hub for:
โ
Finance (Mortgage, Interest, Inflation)
โ
Tech (Base64, JSON, Dev Suite, IP)
โ
Health (BMI, BMR, TDEE)
โ
Productivity (Timer, Workspace, QR)
โก๏ธ Fast & Private
๐ No data leaves your device
๐ 100% Free
๐ Use it now: https://tools.kandz.me
๐ Bookmark itโyouโll need it later!