|

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 splittingYesNo
Pathname expansionYesNo
Quote variablesRequiredOptional
&& / || insideNoYes
Regex =~NoYes
Pattern matching ==NoYes
< / >Escape neededBare works
Parentheses groupingNoYes

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 [[ ]] whenUse [ ] when
Writing bash scriptsNeed POSIX portability
You want regex matchingRunning under sh or dash
You want glob patternsWriting 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:

OperatorMeaning
+Addition
-Subtraction
*Multiplication
/Division
%Modulus (remainder)
**Exponentiation
++Increment
--Decrement
+=, -=, *=, /=Compound assignment

Key points:

  1. Integer arithmetic only โ€” (( )) supports only integer math. For floating point, use bc or awk.
  2. Expression evaluation โ€” the entire expression is evaluated to a single integer value.
  3. 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 / 3 is 1 โ€” integer division truncates. 5 % 3 is 2 โ€” 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:

FormPurposeExample
$((...))Produce a valuex=$((a + b))
((...))Evaluate, set exit status((a > b))
letOlder alternativelet x=a+b

$((...)) vs ((...)):

  • $((...)) produces output โ€” you capture it or print it
  • ((...)) sets an exit status โ€” useful in if
# $(( )) 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):

OperatorMeaning
&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:

MethodExampleNotes
$(( ))x=$((a+b))Modern, preferred
(( ))((a++))For side effects
letlet x=a+bOlder, still works
exprx=$(expr $a + $b)Obsolete, avoid
bcecho "a+b" | bcFor floating point

Rule of thumb: Use $(( )) for producing values, (( )) for conditions and side effects. Never use expr in 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 requiredYesNo
Word splittingYesNo
Glob expansionYesNo
&& insideโŒโœ…
|| insideโŒโœ…
Regex =~โŒโœ…
Glob ==โŒโœ…
< / >EscapeBare
Grouping ()โŒโœ…

[[ ]] Operators

OperatorMeaning
= / ==String equality
!=String inequality
=~Regex match
-eqโ€“-geNumeric comparisons
-fโ€“-xFile tests
&&AND
||OR
!NOT
( )Grouping

(( )) Arithmetic

OperatorMeaning
+Addition
-Subtraction
*Multiplication
/Integer division
%Modulus
**Exponentiation
++ / --Increment / decrement
+= -= *= /=Compound assignment
& | ^ ~ << >>Bitwise

Three Forms of Arithmetic

FormPurposeExample
$(( ))Produce a valuex=$((a+b))
(( ))Evaluate, set status((a > b))
letOlder alternativelet x=a+b

(( )) in Conditions

ExpressionMeaning
((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

ToolExample
bcecho "scale=2; 10/3" | bc
awkawk '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

PitfallProblemSolution
[[ ]] in shNot POSIXUse [ ] or bash shebang
Quoted regexLiteral matchDon’t quote the pattern
Floats in (( ))TruncatedUse bc or awk
= vs == in [[ ]]Both workFine either way
((a=5))Assignment, not compareUse ((a == 5))
Missing $ in $(( ))Variable names OK$((a + b)) works
(( )) with stringsErrorUse [[ ]] 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

ConceptSyntaxExample
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 forfor ((...))for ((i=0;i<5;i++))
Float with bc| bcecho "10/3" | bc
Float with awkawkawk '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 โ€” for sh or dash, use [ ]
  • $(( )) produces a value โ€” capture it or print it
  • (( )) sets an exit status โ€” use it in if and for side effects
  • Arithmetic is integer-only โ€” use bc or awk for 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 than seq for 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!