|

Linux CLI 68 ๐Ÿง operators in shell scripts

โฑ๏ธ Estimated read: 20 min | |

#!/bin/bash

# Arithmetic operations
num1=10
num2=5
sum=$(( num1 + num2 ))
difference=$(( num1 - num2 ))
product=$(( num1 * num2 ))
quotient=$(( num1 / num2 ))
remainder=$(( num1 % num2 ))

echo "Sum: $sum"
echo "Difference: $difference"
echo "Product: $product"
echo "Quotient: $quotient"
echo "Remainder: $remainder"

# Relational operations
if [ "$num1" -gt "$num2" ]; then
    echo "$num1 is greater than $num2."
elif [ "$num1" -lt "$num2" ]; then
    echo "$num1 is less than $num2."
else
    echo "$num1 is equal to $num2."
fi

# Logical operations
if [ "$num1" -gt 0 ] && [ "$num2" -gt 0 ]; then
    echo "Both numbers are positive."
elif [ "$num1" -lt 0 ] || [ "$num2" -lt 0 ]; then
    echo "At least one number is negative."
else
    echo "One or both numbers are zero."
fi

# String operations
str1="Hello"
str2="World"

if [ "$str1" = "$str2" ]; then
    echo "The strings are equal."
elif [ "$str1" \< "$str2" ]; then
    echo "\"$str1\" is less than \"$str2\" in ASCII order."
else
    echo "\"$str1\" is greater than \"$str2\" in ASCII order."
fi

# File test operations
if [ -e "/etc/passwd" ]; then
    echo "/etc/passwd exists."
fi

if [ -f "/etc/passwd" ]; then
    echo "/etc/passwd is a regular file."
fi

if [ -d "/etc" ]; then
    echo "/etc is a directory."
fi

# Assignment operations
x=10
y=5
x=$(( x + y ))
echo "After addition, x = $x"

# Bitwise AND operation
num1=60    # Binary: 00111100
num2=13    # Binary: 00001101
and_result=$(( num1 & num2 ))

echo "Bitwise AND of $num1 and $num2 is: $and_result"

# Bitwise OR operation
or_result=$(( num1 | num2 ))

echo "Bitwise OR of $num1 and $num2 is: $or_result"

# Bitwise XOR operation
xor_result=$(( num1 ^ num2 ))

echo "Bitwise XOR of $num1 and $num2 is: $xor_result"

# Bitwise NOT operation (negation)
not_result=$(( ~num1 ))

echo "Bitwise NOT of $num1 is: $not_result"

# Left shift operation
left_shift=$(( num1 << 2 ))

echo "Left shift of $num1 by 2 bits is: $left_shift"

# Right shift operation
right_shift=$(( num1 >> 2 ))

echo "Right shift of $num1 by 2 bits is: $right_shift"

Shell scripts use operators to perform operations on variables, strings, numbers, and files. They fall into a handful of categories โ€” arithmetic, relational, logical, assignment, file test, string, and bitwise. Knowing which operator to use in which context is half the battle in shell scripting.

Key point: The operator you use depends on where you use it. Inside $((...)) you use C-style operators (+, -, *, /). Inside [ ] you use alphabetic operators (-eq, -lt). Inside [[ ]] you can use either. Mixing them up is the #1 source of bugs.


a – unary, assignment and logical operators in shell scripts

Shell scripts use various operators to perform operations on variables, strings, numbers, and other data types.

Common categories of operators:

CategoryPurpose
UnaryOperate on one operand (+, -, !)
ArithmeticMath on numbers (+, -, *, /, %)
RelationalCompare numbers or strings (-eq, -lt)
LogicalCombine conditions (&&, ||, !)
AssignmentStore values (=, +=, -=)
File testTest file properties (-f, -d, -x)
StringCompare strings (=, !=, <, >)
BitwiseOperate on individual bits (&, |, ^)

Unary operators:

“Unary” refers to the number of operands โ€” these take one operand. There are two unary operators, + and -, which indicate whether a number is positive or negative.

$ x=5
$ echo $(( -x ))
[ -5 ]
$ echo $(( +x ))
[ 5 ]

$ y=-10
$ echo $(( -y ))
[ 10 ]

There’s also the logical NOT !, which negates a condition:

$ [ ! -f /nonexistent ] && echo "not a file"
[ not a file ]

Assignment operators:

OperatorMeaningExample
=Simple assignmentx=10
+=Add and assign((x += 5))
-=Subtract and assign((x -= 3))
*=Multiply and assign((x *= 2))
/=Divide and assign((x /= 4))
%=Modulus and assign((x %= 3))
$ 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 ]

Note: The = in x=10 is a variable assignment, not an operator you use inside $(( )). Inside arithmetic, use == for comparison.

Logical operators:

OperatorMeaning
&&Logical AND
||Logical OR
!Logical NOT
$ a=10
$ b=5

$ if [ "$a" -gt 0 ] && [ "$b" -gt 0 ]; then
>     echo "Both positive"
> fi
[ Both positive ]

$ if [ "$a" -lt 0 ] || [ "$b" -lt 0 ]; then
>     echo "At least one negative"
> else
>     echo "Neither negative"
> fi
[ Neither negative ]

$ if [ ! -f /nonexistent ]; then
>     echo "File not found"
> fi
[ File not found ]

Short-circuit evaluation:

&& and || are short-circuit โ€” they stop as soon as the result is determined:

# && โ€” if the first fails, the second isn't run
$ [ -f /nonexistent ] && echo "never printed"

# || โ€” if the first succeeds, the second isn't run
$ [ -d /etc ] || echo "never printed"

This makes them useful for conditional execution:

$ command && echo "success" || echo "failed"

Combining logic inside [[ ]]:

$ if [[ $a -gt 0 && $b -gt 0 ]]; then
>     echo "Both positive"
> fi
[ Both positive ]

With [[ ]], you don’t need separate brackets for each condition.


b – Arithmetic relational and string operators in shell scripts

Arithmetic operators:

OperatorMeaning
+Addition
-Subtraction
*Multiplication
/Division (integer only)
%Modulus (remainder)
**Exponentiation
++Increment
--Decrement
$ num1=10
$ num2=5

$ sum=$(( num1 + num2 ))
$ difference=$(( num1 - num2 ))
$ product=$(( num1 * num2 ))
$ quotient=$(( num1 / num2 ))
$ remainder=$(( num1 % num2 ))

$ echo "Sum: $sum"
$ echo "Difference: $difference"
$ echo "Product: $product"
$ echo "Quotient: $quotient"
$ echo "Remainder: $remainder"
[ Sum: 15 ]
[ Difference: 5 ]
[ Product: 50 ]
[ Quotient: 2 ]
[ Remainder: 0 ]

Increment and decrement:

$ i=5
$ (( i++ )); echo $i
[ 6 ]
$ (( i-- )); echo $i
[ 5 ]
$ (( ++i )); echo $i
[ 6 ]
$ (( --i )); echo $i
[ 5 ]
FormMeaning
i++Use, then increment (post)
++iIncrement, then use (pre)
i--Use, then decrement (post)
--iDecrement, then use (pre)

Integer division and modulus:

$ echo $(( 10 / 3 ))
[ 3 ]                # truncates, not 3.333
$ echo $(( 10 % 3 ))
[ 1 ]                # remainder
$ echo $(( 10 ** 3 ))
[ 1000 ]             # exponentiation

Note: Bash arithmetic is integer only. For decimals, use bc or awk.

Relational operators:

Two syntaxes โ€” alphabetic (for [ ]) and C-style (for (( )) and [[ ]]):

AlphabeticC-styleMeaning
-lt<Less than
-gt>Greater than
-le<=Less than or equal
-ge>=Greater than or equal
-eq==Equal to
-ne!=Not equal to
$ num1=10
$ num2=5

$ if [ "$num1" -gt "$num2" ]; then
>     echo "$num1 is greater than $num2."
> elif [ "$num1" -lt "$num2" ]; then
>     echo "$num1 is less than $num2."
> else
>     echo "$num1 is equal to $num2."
> fi
[ 10 is greater than 5. ]

The same in [[ ]] with C-style operators:

$ if [[ $num1 > $num2 ]]; then
>     echo "$num1 > $num2"
> fi
[ 10 > 5 ]

โš ๏ธ Warning: Inside [ ], < and > are redirection operators โ€” you must escape them (\<, \>). Inside [[ ]], they work bare. This is why [[ ]] is safer.

String operators:

OperatorMeaning
= or ==Equal to
!=Not equal to
<Less than (ASCII)
>Greater than (ASCII)
-zEmpty string
-nNon-empty string
$ str1="Hello"
$ str2="World"

$ if [ "$str1" = "$str2" ]; then
>     echo "The strings are equal."
> elif [ "$str1" \< "$str2" ]; then
>     echo "\"$str1\" is less than \"$str2\" in ASCII order."
> else
>     echo "\"$str1\" is greater than \"$str2\" in ASCII order."
> fi
[ "Hello" is less than "World" in ASCII order. ]

H (72) is less than W (87) in ASCII, so Hello < World.

Always quote strings in [ ]:

# โŒ Breaks if $name is empty
[ $name = "Alice" ]

# โœ… Safe
[ "$name" = "Alice" ]

Numbers vs strings โ€” the classic bug:

# โŒ Comparing numbers as strings
$ [ "10" = "10.0" ] && echo "equal" || echo "different"
[ different ]

# โŒ Comparing strings as numbers
$ [ "abc" -eq "def" ]
[ bash: [: abc: integer expression expected ]

Use = for strings, -eq for numbers. Never mix them.


c – file test and bit operators in shell scripts

File test operators:

OperatorTrue if
-eFile exists
-fRegular file
-dDirectory
-rReadable
-wWritable
-xExecutable
-sNon-zero size
-LSymlink
-pNamed pipe
-SSocket
$ if [ -e "/etc/passwd" ]; then
>     echo "/etc/passwd exists."
> fi
[ /etc/passwd exists. ]

$ if [ -f "/etc/passwd" ]; then
>     echo "/etc/passwd is a regular file."
> fi
[ /etc/passwd is a regular file. ]

$ if [ -d "/etc" ]; then
>     echo "/etc is a directory."
> fi
[ /etc is a directory. ]

File comparison operators:

OperatorTrue if
f1 -nt f2f1 newer than f2
f1 -ot f2f1 older than f2
f1 -ef f2Same file (inode)
$ [ file1.txt -nt file2.txt ] && echo "file1 is newer"
$ [ /etc/passwd -ef /etc/passwd ] && echo "same file"

Combining file tests:

# File exists AND readable
if [ -f "$file" ] && [ -r "$file" ]; then
    echo "Can read $file"
fi

# File OR directory
if [ -f "$path" ] || [ -d "$path" ]; then
    echo "Path exists"
fi

Bitwise operators:

Bitwise operators perform operations on individual bits of a number.

OperatorMeaning
&Bitwise AND
|Bitwise OR
^Bitwise XOR (exclusive OR)
~Bitwise NOT (negation)
<<Left shift
>>Right shift
$ num1=60    # Binary: 00111100
$ num2=13    # Binary: 00001101

Bitwise AND (&):

Both bits must be 1 for the result to be 1.

$ and_result=$(( num1 & num2 ))
$ echo "Bitwise AND of $num1 and $num2 is: $and_result"
[ Bitwise AND of 60 and 13 is: 12 ]
  60:  00111100
  13:  00001101
  &    00001100  = 12

Bitwise OR (|):

At least one bit must be 1 for the result to be 1.

$ or_result=$(( num1 | num2 ))
$ echo "Bitwise OR of $num1 and $num2 is: $or_result"
[ Bitwise OR of 60 and 13 is: 61 ]
  60:  00111100
  13:  00001101
  |    00111101  = 61

Bitwise XOR (^):

Bits must be different for the result to be 1.

$ xor_result=$(( num1 ^ num2 ))
$ echo "Bitwise XOR of $num1 and $num2 is: $xor_result"
[ Bitwise XOR of 60 and 13 is: 49 ]
  60:  00111100
  13:  00001101
  ^    00110001  = 49

Bitwise NOT (~):

Flips every bit.

$ not_result=$(( ~num1 ))
$ echo "Bitwise NOT of $num1 is: $not_result"
[ Bitwise NOT of 60 is: -61 ]

Why -61? Because bash uses two’s complement for negative numbers. ~60 = -(60+1) = -61.

Left shift (<<):

Shifts bits to the left by N positions โ€” equivalent to multiplying by 2^N.

$ left_shift=$(( num1 << 2 ))
$ echo "Left shift of $num1 by 2 bits is: $left_shift"
[ Left shift of 60 by 2 bits is: 240 ]
  60 << 2  =  60 ร— 4  = 240

Right shift (>>):

Shifts bits to the right by N positions โ€” equivalent to dividing by 2^N.

$ right_shift=$(( num1 >> 2 ))
$ echo "Right shift of $num1 by 2 bits is: $right_shift"
[ Right shift of 60 by 2 bits is: 15 ]
  60 >> 2  =  60 รท 4  = 15

Common uses of bitwise operators:

Use caseOperator
Permission masks& (test), | (set)
Flags&, |, ^
Power of 2 multiply/divide<<, >>
Toggle bits^
Invert bits~

Practical example โ€” bitmask flags:

READ=0x01      # 0001
WRITE=0x02     # 0010
EXEC=0x04      # 0100

flags=0
(( flags |= READ ))       # set read
(( flags |= EXEC ))       # set exec
# flags = 0101 = 5

# Test
(( flags & READ ))  && echo "read enabled"
(( flags & WRITE )) && echo "write enabled"
(( flags & EXEC ))  && echo "exec enabled"
[ read enabled ]
[ exec enabled ]

Practical example โ€” permission check:

# Check if a file is world-writable
perms=$(stat -c %a "$file")
if (( 0$perms & 002 )); then
    echo "File is world-writable!"
fi

Complete Example Session

# ============================================
# PART 1: ARITHMETIC
# ============================================

$ num1=10
$ num2=5
$ echo $(( num1 + num2 ))
[ 15 ]
$ echo $(( num1 - num2 ))
[ 5 ]
$ echo $(( num1 * num2 ))
[ 50 ]
$ echo $(( num1 / num2 ))
[ 2 ]
$ echo $(( num1 % num2 ))
[ 0 ]

# ============================================
# PART 2: INCREMENT / DECREMENT
# ============================================

$ i=5
$ (( i++ )); echo $i
[ 6 ]
$ (( i-- )); echo $i
[ 5 ]

# ============================================
# PART 3: RELATIONAL
# ============================================

$ if [ "$num1" -gt "$num2" ]; then
>     echo "$num1 is greater than $num2."
> elif [ "$num1" -lt "$num2" ]; then
>     echo "$num1 is less than $num2."
> else
>     echo "$num1 is equal to $num2."
> fi
[ 10 is greater than 5. ]

# ============================================
# PART 4: LOGICAL
# ============================================

$ if [ "$num1" -gt 0 ] && [ "$num2" -gt 0 ]; then
>     echo "Both numbers are positive."
> elif [ "$num1" -lt 0 ] || [ "$num2" -lt 0 ]; then
>     echo "At least one number is negative."
> else
>     echo "One or both numbers are zero."
> fi
[ Both numbers are positive. ]

# ============================================
# PART 5: STRING
# ============================================

$ str1="Hello"
$ str2="World"

$ if [ "$str1" = "$str2" ]; then
>     echo "The strings are equal."
> elif [ "$str1" \< "$str2" ]; then
>     echo "\"$str1\" is less than \"$str2\" in ASCII order."
> else
>     echo "\"$str1\" is greater than \"$str2\" in ASCII order."
> fi
[ "Hello" is less than "World" in ASCII order. ]

# ============================================
# PART 6: FILE TESTS
# ============================================

$ [ -e "/etc/passwd" ] && echo "/etc/passwd exists."
[ /etc/passwd exists. ]
$ [ -f "/etc/passwd" ] && echo "regular file"
[ regular file ]
$ [ -d "/etc" ] && echo "directory"
[ directory ]

# ============================================
# PART 7: ASSIGNMENT
# ============================================

$ x=10
$ y=5
$ x=$(( x + y ))
$ echo "x = $x"
[ x = 15 ]

$ (( x += 5 )); echo $x
[ 20 ]
$ (( x -= 3 )); echo $x
[ 17 ]
$ (( x *= 2 )); echo $x
[ 34 ]

# ============================================
# PART 8: BITWISE AND
# ============================================

$ num1=60
$ num2=13
$ echo $(( num1 & num2 ))
[ 12 ]

# ============================================
# PART 9: BITWISE OR
# ============================================

$ echo $(( num1 | num2 ))
[ 61 ]

# ============================================
# PART 10: BITWISE XOR
# ============================================

$ echo $(( num1 ^ num2 ))
[ 49 ]

# ============================================
# PART 11: BITWISE NOT
# ============================================

$ echo $(( ~num1 ))
[ -61 ]

# ============================================
# PART 12: LEFT SHIFT
# ============================================

$ echo $(( num1 << 2 ))
[ 240 ]

# ============================================
# PART 13: RIGHT SHIFT
# ============================================

$ echo $(( num1 >> 2 ))
[ 15 ]

# ============================================
# PART 14: BITMASK FLAGS
# ============================================

$ READ=0x01
$ WRITE=0x02
$ EXEC=0x04

$ flags=0
$ (( flags |= READ ))
$ (( flags |= EXEC ))
$ echo "Flags: $flags"
[ Flags: 5 ]

$ (( flags & READ ))  && echo "read enabled"
$ (( flags & WRITE )) && echo "write enabled"
$ (( flags & EXEC ))  && echo "exec enabled"
[ read enabled ]
[ exec enabled ]

# ============================================
# PART 15: OPERATOR CONTEXTS
# ============================================

# Same comparison, three ways
$ a=10
$ b=5

$ [ "$a" -gt "$b" ] && echo "1: greater"
[ 1: greater ]
$ [[ $a -gt $b ]] && echo "2: greater"
[ 2: greater ]
$ (( a > b )) && echo "3: greater"
[ 3: greater ]

# ============================================
# PART 16: FULL SCRIPT
# ============================================

$ cat > ops.sh << 'EOF'
#!/bin/bash

num1=10
num2=5
sum=$(( num1 + num2 ))
difference=$(( num1 - num2 ))
product=$(( num1 * num2 ))
quotient=$(( num1 / num2 ))
remainder=$(( num1 % num2 ))

echo "Sum: $sum"
echo "Difference: $difference"
echo "Product: $product"
echo "Quotient: $quotient"
echo "Remainder: $remainder"

if [ "$num1" -gt "$num2" ]; then
    echo "$num1 is greater than $num2."
elif [ "$num1" -lt "$num2" ]; then
    echo "$num1 is less than $num2."
else
    echo "$num1 is equal to $num2."
fi

if [ "$num1" -gt 0 ] && [ "$num2" -gt 0 ]; then
    echo "Both numbers are positive."
elif [ "$num1" -lt 0 ] || [ "$num2" -lt 0 ]; then
    echo "At least one number is negative."
else
    echo "One or both numbers are zero."
fi

str1="Hello"
str2="World"

if [ "$str1" = "$str2" ]; then
    echo "The strings are equal."
elif [ "$str1" \< "$str2" ]; then
    echo "\"$str1\" is less than \"$str2\" in ASCII order."
else
    echo "\"$str1\" is greater than \"$str2\" in ASCII order."
fi

if [ -e "/etc/passwd" ]; then
    echo "/etc/passwd exists."
fi

if [ -f "/etc/passwd" ]; then
    echo "/etc/passwd is a regular file."
fi

if [ -d "/etc" ]; then
    echo "/etc is a directory."
fi

x=10
y=5
x=$(( x + y ))
echo "After addition, x = $x"

num1=60
num2=13
and_result=$(( num1 & num2 ))
echo "Bitwise AND of $num1 and $num2 is: $and_result"

or_result=$(( num1 | num2 ))
echo "Bitwise OR of $num1 and $num2 is: $or_result"

xor_result=$(( num1 ^ num2 ))
echo "Bitwise XOR of $num1 and $num2 is: $xor_result"

not_result=$(( ~num1 ))
echo "Bitwise NOT of $num1 is: $not_result"

left_shift=$(( num1 << 2 ))
echo "Left shift of $num1 by 2 bits is: $left_shift"

right_shift=$(( num1 >> 2 ))
echo "Right shift of $num1 by 2 bits is: $right_shift"
EOF
$ chmod +x ops.sh
$ ./ops.sh
[ Sum: 15 ]
[ Difference: 5 ]
[ Product: 50 ]
[ Quotient: 2 ]
[ Remainder: 0 ]
[ 10 is greater than 5. ]
[ Both numbers are positive. ]
[ "Hello" is less than "World" in ASCII order. ]
[ /etc/passwd exists. ]
[ /etc/passwd is a regular file. ]
[ /etc is a directory. ]
[ After addition, x = 15 ]
[ Bitwise AND of 60 and 13 is: 12 ]
[ Bitwise OR of 60 and 13 is: 61 ]
[ Bitwise XOR of 60 and 13 is: 49 ]
[ Bitwise NOT of 60 is: -61 ]
[ Left shift of 60 by 2 bits is: 240 ]
[ Right shift of 60 by 2 bits is: 15 ]

Quick Reference

Operator Categories

CategoryOperatorsContext
Unary+, -, !$(( )), [ ]
Arithmetic+ - * / % **$(( ))
Increment++, --$(( ))
Relational (num)-eq -ne -lt -le -gt -ge[ ]
Relational (C)== != < <= > >=(( )), [[ ]]
Logical&&, ||, !anywhere
Assignment= += -= *= /= %=shell / (( ))
String= != < > -z -n[ ], [[ ]]
File test-e -f -d -r -w -x -s -L[ ], [[ ]]
File compare-nt -ot -ef[ ], [[ ]]
Bitwise& | ^ ~ << >>$(( ))

Arithmetic Operators

OperatorMeaningExample
+Addition$((a + b))
-Subtraction$((a - b))
*Multiplication$((a * b))
/Integer division$((a / b))
%Modulus$((a % b))
**Exponentiation$((a ** b))
++Increment((i++))
--Decrement((i--))

Relational Operators

AlphabeticC-styleMeaning
-eq==Equal
-ne!=Not equal
-lt<Less than
-le<=Less or equal
-gt>Greater than
-ge>=Greater or equal

String Operators

OperatorMeaning
= / ==Equal
!=Not equal
<Less (ASCII)
>Greater (ASCII)
-zEmpty
-nNon-empty

File Test Operators

OperatorTrue if
-eExists
-fRegular file
-dDirectory
-rReadable
-wWritable
-xExecutable
-sNon-empty
-LSymlink

Bitwise Operators

OperatorMeaningExample
&AND$((a & b))
|OR$((a | b))
^XOR$((a ^ b))
~NOT$((~a))
<<Left shift$((a << 2))
>>Right shift$((a >> 2))

Logical Operators

OperatorMeaning
&&AND
||OR
!NOT

Best Practices

โœ… Do This:

# Use arithmetic operators inside $(( ))
sum=$(( a + b ))                       # โœ…

# Use -eq/-lt for numeric comparison in [ ]
if [ "$a" -gt "$b" ]; then ...; fi     # โœ…

# Use C-style in [[ ]] or (( ))
if [[ $a > $b ]]; then ...; fi         # โœ…
if (( a > b )); then ...; fi           # โœ…

# Quote variables in [ ]
if [ "$str" = "value" ]; then ...; fi  # โœ…

# Escape < and > in [ ]
if [ "$a" \< "$b" ]; then ...; fi      # โœ…

# Use == for numbers in [[ ]] or (( ))
if [[ $a == $b ]]; then ...; fi        # โœ…

# Use bitwise masks for flags
(( flags |= READ ))                    # โœ…

# Combine file tests with &&
if [ -f "$f" ] && [ -r "$f" ]; then ...; fi  # โœ…

โŒ Don’t Do This:

# Don't use = for numbers
if [ "$a" = 5 ]; then ...; fi          # โš ๏ธ  string compare
if [ "$a" -eq 5 ]; then ...; fi        # โœ…

# Don't use -eq for strings
if [ "$name" -eq "Alice" ]; then ...; fi  # โŒ error
if [ "$name" = "Alice" ]; then ...; fi    # โœ…

# Don't use < > unescaped in [ ]
if [ "$a" > "$b" ]; then ...; fi       # โŒ creates file "b"
if [ "$a" \> "$b" ]; then ...; fi      # โœ…
if [[ $a > $b ]]; then ...; fi         # โœ…

# Don't forget spaces around [ ]
if [$a -gt 0]; then ...; fi            # โŒ syntax error

# Don't mix arithmetic and string contexts
echo $(( name ))                       # โŒ variable must be a number

# Don't expect floating point
echo $(( 10 / 3 ))                     # โŒ gives 3, not 3.33
echo "scale=2; 10/3" | bc              # โœ…

# Don't use && inside [ ]
if [ "$a" -gt 0 && "$b" -gt 0 ]; then ...; fi  # โŒ
if [ "$a" -gt 0 ] && [ "$b" -gt 0 ]; then ...; fi  # โœ…
if [[ $a -gt 0 && $b -gt 0 ]]; then ...; fi        # โœ…

# Don't confuse = with == inside (( ))
(( x = 5 ))                            # โŒ assignment
(( x == 5 ))                           # โœ… comparison

Common Pitfalls

PitfallProblemSolution
= for numbersString compareUse -eq
-eq for stringsErrorUse =
< unescaped in [ ]Redirection\< or use [[ ]]
&& inside [ ]Syntax errorSeparate brackets or use [[ ]]
Floating pointTruncatedUse bc or awk
Missing spacesSyntax error[ -f f ]
Unquoted variableWord splittingQuote it
= vs == in (( ))Assignment vs compareUse == for compare

Real-World Examples

1. Arithmetic Operations

#!/bin/bash
num1=10
num2=5
sum=$(( num1 + num2 ))
difference=$(( num1 - num2 ))
product=$(( num1 * num2 ))
quotient=$(( num1 / num2 ))
remainder=$(( num1 % num2 ))

echo "Sum: $sum"
echo "Difference: $difference"
echo "Product: $product"
echo "Quotient: $quotient"
echo "Remainder: $remainder"
[ Sum: 15 ]
[ Difference: 5 ]
[ Product: 50 ]
[ Quotient: 2 ]
[ Remainder: 0 ]

2. Relational Operations

#!/bin/bash
num1=10
num2=5
if [ "$num1" -gt "$num2" ]; then
    echo "$num1 is greater than $num2."
elif [ "$num1" -lt "$num2" ]; then
    echo "$num1 is less than $num2."
else
    echo "$num1 is equal to $num2."
fi
[ 10 is greater than 5. ]

3. Logical Operations

#!/bin/bash
num1=10
num2=5
if [ "$num1" -gt 0 ] && [ "$num2" -gt 0 ]; then
    echo "Both numbers are positive."
elif [ "$num1" -lt 0 ] || [ "$num2" -lt 0 ]; then
    echo "At least one number is negative."
else
    echo "One or both numbers are zero."
fi
[ Both numbers are positive. ]

4. String Comparison

#!/bin/bash
str1="Hello"
str2="World"

if [ "$str1" = "$str2" ]; then
    echo "The strings are equal."
elif [ "$str1" \< "$str2" ]; then
    echo "\"$str1\" is less than \"$str2\" in ASCII order."
else
    echo "\"$str1\" is greater than \"$str2\" in ASCII order."
fi
[ "Hello" is less than "World" in ASCII order. ]

5. File Tests

#!/bin/bash
if [ -e "/etc/passwd" ]; then
    echo "/etc/passwd exists."
fi
if [ -f "/etc/passwd" ]; then
    echo "/etc/passwd is a regular file."
fi
if [ -d "/etc" ]; then
    echo "/etc is a directory."
fi

6. Assignment

#!/bin/bash
x=10
y=5
x=$(( x + y ))
echo "After addition, x = $x"
[ After addition, x = 15 ]

7. Bitwise AND

#!/bin/bash
num1=60
num2=13
echo "Bitwise AND: $(( num1 & num2 ))"
[ Bitwise AND: 12 ]

8. Bitwise OR

#!/bin/bash
num1=60
num2=13
echo "Bitwise OR: $(( num1 | num2 ))"
[ Bitwise OR: 61 ]

9. Bitwise XOR

#!/bin/bash
num1=60
num2=13
echo "Bitwise XOR: $(( num1 ^ num2 ))"
[ Bitwise XOR: 49 ]

10. Bitwise NOT

#!/bin/bash
num1=60
echo "Bitwise NOT: $(( ~num1 ))"
[ Bitwise NOT: -61 ]

11. Left Shift

#!/bin/bash
num1=60
echo "Left shift: $(( num1 << 2 ))"
[ Left shift: 240 ]

12. Right Shift

#!/bin/bash
num1=60
echo "Right shift: $(( num1 >> 2 ))"
[ Right shift: 15 ]

13. Increment and Decrement

#!/bin/bash
i=5
(( i++ )); echo "$i"
(( i-- )); echo "$i"
(( ++i )); echo "$i"
(( --i )); echo "$i"
[ 6 ]
[ 5 ]
[ 6 ]
[ 5 ]

14. Compound Assignment

#!/bin/bash
x=10
(( x += 5 )); echo "$x"
(( x -= 3 )); echo "$x"
(( x *= 2 )); echo "$x"
(( x /= 4 )); echo "$x"
[ 15 ]
[ 12 ]
[ 24 ]
[ 6 ]

15. Bitmask Flags

#!/bin/bash
READ=0x01
WRITE=0x02
EXEC=0x04

flags=0
(( flags |= READ ))
(( flags |= EXEC ))

(( flags & READ ))  && echo "read enabled"
(( flags & WRITE )) && echo "write enabled"
(( flags & EXEC ))  && echo "exec enabled"
[ read enabled ]
[ exec enabled ]

16. Test If Power of 2

#!/bin/bash
n=32
if (( n > 0 && (n & (n - 1)) == 0 )); then
    echo "$n is a power of 2"
fi
[ 32 is a power of 2 ]

17. Swap Two Numbers

#!/bin/bash
a=5
b=10
a=$(( a ^ b ))
b=$(( a ^ b ))
a=$(( a ^ b ))
echo "a=$a b=$b"
[ a=10 b=5 ]

18. Numeric Validation

#!/bin/bash
read -p "Enter a number: " n
if [[ "$n" =~ ^-?[0-9]+$ ]]; then
    echo "Valid integer: $n"
else
    echo "Not an integer"
fi

19. Even/Odd

#!/bin/bash
n=7
if (( n % 2 == 0 )); then
    echo "even"
else
    echo "odd"
fi
[ odd ]

20. Full Script

#!/bin/bash

num1=10
num2=5
sum=$(( num1 + num2 ))
difference=$(( num1 - num2 ))
product=$(( num1 * num2 ))
quotient=$(( num1 / num2 ))
remainder=$(( num1 % num2 ))

echo "Sum: $sum"
echo "Difference: $difference"
echo "Product: $product"
echo "Quotient: $quotient"
echo "Remainder: $remainder"

if [ "$num1" -gt "$num2" ]; then
    echo "$num1 is greater than $num2."
elif [ "$num1" -lt "$num2" ]; then
    echo "$num1 is less than $num2."
else
    echo "$num1 is equal to $num2."
fi

if [ "$num1" -gt 0 ] && [ "$num2" -gt 0 ]; then
    echo "Both numbers are positive."
elif [ "$num1" -lt 0 ] || [ "$num2" -lt 0 ]; then
    echo "At least one number is negative."
else
    echo "One or both numbers are zero."
fi

str1="Hello"
str2="World"

if [ "$str1" = "$str2" ]; then
    echo "The strings are equal."
elif [ "$str1" \< "$str2" ]; then
    echo "\"$str1\" is less than \"$str2\" in ASCII order."
else
    echo "\"$str1\" is greater than \"$str2\" in ASCII order."
fi

if [ -e "/etc/passwd" ]; then
    echo "/etc/passwd exists."
fi

if [ -f "/etc/passwd" ]; then
    echo "/etc/passwd is a regular file."
fi

if [ -d "/etc" ]; then
    echo "/etc is a directory."
fi

x=10
y=5
x=$(( x + y ))
echo "After addition, x = $x"

num1=60
num2=13
and_result=$(( num1 & num2 ))
echo "Bitwise AND of $num1 and $num2 is: $and_result"

or_result=$(( num1 | num2 ))
echo "Bitwise OR of $num1 and $num2 is: $or_result"

xor_result=$(( num1 ^ num2 ))
echo "Bitwise XOR of $num1 and $num2 is: $xor_result"

not_result=$(( ~num1 ))
echo "Bitwise NOT of $num1 is: $not_result"

left_shift=$(( num1 << 2 ))
echo "Left shift of $num1 by 2 bits is: $left_shift"

right_shift=$(( num1 >> 2 ))
echo "Right shift of $num1 by 2 bits is: $right_shift"

Visual: Operator Categories

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚           Operator categories                โ”‚
โ”‚                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  ARITHMETIC                            โ”‚  โ”‚
โ”‚  โ”‚  + - * / % ** ++ --                    โ”‚  โ”‚
โ”‚  โ”‚  โ†’ inside $(( ))                       โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  RELATIONAL (numeric)                  โ”‚  โ”‚
โ”‚  โ”‚  -eq -ne -lt -le -gt -ge               โ”‚  โ”‚
โ”‚  โ”‚  โ†’ inside [ ]                          โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  RELATIONAL (C-style)                  โ”‚  โ”‚
โ”‚  โ”‚  == != < <= > >=                       โ”‚  โ”‚
โ”‚  โ”‚  โ†’ inside (( )) and [[ ]]              โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  LOGICAL                               โ”‚  โ”‚
โ”‚  โ”‚  && || !                               โ”‚  โ”‚
โ”‚  โ”‚  โ†’ combine conditions                  โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  STRING                                โ”‚  โ”‚
โ”‚  โ”‚  = != < > -z -n                        โ”‚  โ”‚
โ”‚  โ”‚  โ†’ compare text                        โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  FILE TEST                             โ”‚  โ”‚
โ”‚  โ”‚  -e -f -d -r -w -x -s -L               โ”‚  โ”‚
โ”‚  โ”‚  โ†’ test files and dirs                 โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                              โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”  โ”‚
โ”‚  โ”‚  BITWISE                               โ”‚  โ”‚
โ”‚  โ”‚  & | ^ ~ << >>                         โ”‚  โ”‚
โ”‚  โ”‚  โ†’ manipulate bits                     โ”‚  โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜  โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: Bitwise Operations

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚  num1 = 60  =  00111100                      โ”‚
โ”‚  num2 = 13  =  00001101                      โ”‚
โ”‚                                              โ”‚
โ”‚  AND  &   00111100                           โ”‚
โ”‚           00001101                           โ”‚
โ”‚           โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                           โ”‚
โ”‚           00001100  = 12                     โ”‚
โ”‚                                              โ”‚
โ”‚  OR   |   00111100                           โ”‚
โ”‚           00001101                           โ”‚
โ”‚           โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                           โ”‚
โ”‚           00111101  = 61                     โ”‚
โ”‚                                              โ”‚
โ”‚  XOR  ^   00111100                           โ”‚
โ”‚           00001101                           โ”‚
โ”‚           โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                           โ”‚
โ”‚           00110001  = 49                     โ”‚
โ”‚                                              โ”‚
โ”‚  NOT  ~   00111100                           โ”‚
โ”‚           โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€                           โ”‚
โ”‚           11000011  = -61 (two's complement) โ”‚
โ”‚                                              โ”‚
โ”‚  <<  2    00111100 << 2 = 11110000 = 240    โ”‚
โ”‚  >>  2    00111100 >> 2 = 00001111 =  15    โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Visual: Operator Contexts

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚           Which operator where?              โ”‚
โ”‚                                              โ”‚
โ”‚  $(( a + b ))       arithmetic: + - * / %    โ”‚
โ”‚                     comparison: == != < >    โ”‚
โ”‚                     bitwise:    & | ^ ~ << >>โ”‚
โ”‚                                              โ”‚
โ”‚  [ "$a" -gt "$b" ]  numeric: -eq -ne -lt ... โ”‚
โ”‚                     string:  = != -z -n      โ”‚
โ”‚                     file:    -f -d -e ...    โ”‚
โ”‚                                              โ”‚
โ”‚  [[ $a > $b ]]      C-style: == != < >       โ”‚
โ”‚                     also numeric and string  โ”‚
โ”‚                     && || inside             โ”‚
โ”‚                                              โ”‚
โ”‚  (( a > b ))        C-style only             โ”‚
โ”‚                     no strings               โ”‚
โ”‚                                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Summary

CategoryOperatorsUse in
Unary+ - !$(( )), [ ]
Arithmetic+ - * / % **$(( ))
Increment++ --(( ))
Assignment= += -= *= /= %=shell, (( ))
Numeric relational-eq -ne -lt -le -gt -ge[ ]
C-style relational== != < <= > >=(( )), [[ ]]
Logical&& || !conditions
String= != < > -z -n[ ], [[ ]]
File test-e -f -d -r -w -x -s -L[ ], [[ ]]
File compare-nt -ot -ef[ ], [[ ]]
Bitwise& | ^ ~ << >>$(( ))

Key takeaways:

  • Arithmetic operators work in $(( )) โ€” +, -, *, /, %, **
  • Numeric comparisons use -eq, -lt, etc. in [ ]; ==, <, etc. in (( )) and [[ ]]
  • String comparisons use =, !=, <, > โ€” always quote variables in [ ]
  • File tests use -f, -d, -e, -r, -w, -x โ€” check file properties
  • Logical operators &&, ||, ! combine conditions โ€” use separate [ ] brackets or [[ ]]
  • Bitwise operators &, |, ^, ~, <<, >> manipulate bits โ€” useful for flags and masks
  • Increment and decrement ++ and -- work in (( ))
  • Compound assignment +=, -=, *=, /= combine math with assignment
  • Integer only โ€” no floating point in $(( )); use bc or awk
  • Watch out for = vs -eq and = vs == โ€” mixing them is the most common bug
  • Escape < and > in [ ] or use [[ ]]

Remember: The right operator depends on the context. Inside $(( )), use math symbols. Inside [ ], use alphabetic test operators. Inside (( )) and [[ ]], use C-style. And always match the operator to the type โ€” -eq for numbers, = for strings, -f for files. Get this right, and your conditions will be correct and portable.

Was this helpful?


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!