Operators
Chapter 6: Operators in Bash
Section titled “Chapter 6: Operators in Bash”Overview
Section titled “Overview”Operators are the building blocks that allow you to perform operations on variables and values. In this chapter, we’ll cover arithmetic operators, comparison operators, logical operators, and special operators used in bash scripting. This knowledge is essential for writing conditional logic and performing calculations in your scripts.
Operator Types Overview
Section titled “Operator Types Overview”┌─────────────────────────────────────────────────────────────────────┐│ OPERATOR TYPES IN BASH │└─────────────────────────────────────────────────────────────────────┘
┌──────────────────┬──────────────────────────────────────────────────┐│ Type │ Description │├──────────────────┼──────────────────────────────────────────────────┤│ Arithmetic │ +, -, *, /, %, ++, --, etc. ││ Comparison │ -eq, -ne, -lt, -le, -gt, -ge (numeric) ││ │ =, ==, != (string) ││ Logical │ &&, ||, ! ││ Bitwise │ &, |, ^, ~, <<, >> ││ File Tests │ -f, -d, -r, -w, -x, -e, -s, etc. ││ String Tests │ -z, -n, ==, != ││ Compound │ ( ), !, -a, -o │└──────────────────┴──────────────────────────────────────────────────┘Arithmetic Operators
Section titled “Arithmetic Operators”Basic Arithmetic
Section titled “Basic Arithmetic”#!/usr/bin/env bash# Additiona=10b=20sum=$((a + b))echo "$a + $b = $sum" # 10 + 20 = 30
# Subtractiondiff=$((b - a))echo "$b - $a = $diff" # 20 - 10 = 10
# Multiplicationproduct=$((a * b))echo "$a * $b = $product" # 10 * 20 = 200
# Division (integer)quotient=$((b / a))echo "$b / $a = $quotient" # 20 / 10 = 2
# Division with floating pointresult=$(echo "scale=2; $b / $a" | bc)echo "$b / $a = $result" # 20 / 10 = 2.00
# Modulo (remainder)mod=$((b % a))echo "$b % $a = $mod" # 20 % 10 = 0Increment and Decrement
Section titled “Increment and Decrement”#!/usr/bin/env bash# Pre-incrementi=5echo "Before: $i"echo "++i = $((++i))" # i becomes 6, returns 6echo "After: $i" # 6
# Post-incrementi=5echo "Before: $i"echo "i++ = $((i++))" # returns 5, i becomes 6echo "After: $i" # 6
# Pre-decrementi=5echo "Before: $i"echo "--i = $((--i))" # i becomes 4, returns 4echo "After: $i" # 4
# Post-decrementi=5echo "Before: $i"echo "i-- = $((i--))" # returns 5, i becomes 4echo "After: $i" # 4Compound Assignment
Section titled “Compound Assignment”#!/usr/bin/env bash# +=x=10x+=5echo "x = $x" # 15 (concatenation for strings, addition for numbers)
# For stringsstr="Hello"str+=" World"echo "str = $str" # Hello World
# -=x=10x-=3echo "x = $x" # 7
# *=x=5x*=4echo "x = $x" # 20
# /=x=20x/=4echo "x = $x" # 5
# %=x=17x%=5echo "x = $x" # 2Bitwise Operators
Section titled “Bitwise Operators”#!/usr/bin/env bash# Bitwise ANDa=5 # 0101b=3 # 0011result=$((a & b))echo "5 & 3 = $result" # 1 (0001)
# Bitwise ORresult=$((a | b))echo "5 | 3 = $result" # 7 (0111)
# Bitwise XORresult=$((a ^ b))echo "5 ^ 3 = $result" # 6 (0110)
# Bitwise NOTresult=$((~a))echo "~5 = $result" # -6
# Left shiftresult=$((a << 2))echo "5 << 2 = $result" # 20 (0101 -> 10100)
# Right shiftresult=$((a >> 1))echo "5 >> 1 = $result" # 2 (0101 -> 0010)Using let, expr, and bc
Section titled “Using let, expr, and bc”#!/usr/bin/env bash# Using let (arithmetic in let/())let "sum = 10 + 20"let "product = 5 * 6"echo "Sum: $sum, Product: $product"
# Using expr (requires spaces and command substitution)result=$(expr 10 + 5)echo "10 + 5 = $result"
# Using bc for floating pointresult=$(echo "10 / 3" | bc -l)echo "10 / 3 = $result" # 3.33333...
# With scale (precision)result=$(echo "scale=4; 10 / 3" | bc)echo "scale=4: 10 / 3 = $result" # 3.3333
# Complex calculationsresult=$(echo "sqrt(16) + 2^3" | bc -l)echo "sqrt(16) + 2^3 = $result" # 12.00000Comparison Operators
Section titled “Comparison Operators”Numeric Comparison
Section titled “Numeric Comparison”┌─────────────────────────────────────────────────────────────────────┐│ NUMERIC COMPARISON OPERATORS │└─────────────────────────────────────────────────────────────────────┘
┌──────────────────┬──────────────────────────────────────────────────┐│ Operator │ Description │├──────────────────┼──────────────────────────────────────────────────┤│ -eq │ Equal to ││ -ne │ Not equal to ││ -lt │ Less than ││ -le │ Less than or equal to ││ -gt │ Greater than ││ -ge │ Greater than or equal to │└──────────────────┴──────────────────────────────────────────────────┘#!/usr/bin/env basha=10b=20
# Test with [ ] (test command)if [ "$a" -eq 10 ]; then echo "$a equals 10"fi
if [ "$a" -ne "$b" ]; then echo "$a is not equal to $b"fi
if [ "$a" -lt "$b" ]; then echo "$a is less than $b"fi
if [ "$a" -le 10 ]; then echo "$a is less than or equal to 10"fi
if [ "$b" -gt "$a" ]; then echo "$b is greater than $a"fi
if [ "$b" -ge 20 ]; then echo "$b is greater than or equal to 20"fiUsing [[ ]] (Modern Test)
Section titled “Using [[ ]] (Modern Test)”#!/usr/bin/env basha=10b=20
# With [[ ]], you can use < and > for numeric comparison# But these work as string comparison in [ ]# So use (( )) for numeric comparison in bash
# Using (( )) for numeric comparison (recommended)if (( a == 10 )); then echo "$a equals 10"fi
if (( a != b )); then echo "$a is not equal to $b"fi
if (( a < b )); then echo "$a is less than $b"fi
if (( a <= 10 )); then echo "$a is less than or equal to 10"fi
if (( b > a )); then echo "$b is greater than $a"fi
if (( b >= 20 )); then echo "$b is greater than or equal to 20"fiString Comparison
Section titled “String Comparison”┌─────────────────────────────────────────────────────────────────────┐│ STRING COMPARISON OPERATORS │└─────────────────────────────────────────────────────────────────────┘
┌──────────────────┬──────────────────────────────────────────────────┐│ Operator │ Description │├──────────────────┼──────────────────────────────────────────────────┤│ = │ Equal to (or ==) ││ != │ Not equal to ││ < │ Less than (ASCII order) ││ > │ Greater than (ASCII order) ││ -z │ String is null (empty) ││ -n │ String is not null │└──────────────────┴──────────────────────────────────────────────────┘#!/usr/bin/env bashstr1="apple"str2="banana"empty=""space=" "
# Using [ ] (test command) - note quotingif [ "$str1" = "apple" ]; then echo "str1 equals apple"fi
if [ "$str1" != "$str2" ]; then echo "str1 is not equal to str2"fi
# String comparison with < and > (in [ ], must escape or use [[ ]])# These compare based on ASCII/locale orderif [[ "$str1" < "$str2" ]]; then echo "apple comes before banana alphabetically"fi
# Check empty stringif [ -z "$empty" ]; then echo "empty string is null"fi
if [ -n "$str1" ]; then echo "str1 is not empty"fi
# Common mistake: Unquoted variables# WRONG: if [ $str1 = "apple" ]; then # Fails if str1 is empty# RIGHT: if [ "$str1" = "apple" ]; thenLogical Operators
Section titled “Logical Operators”Boolean Operators
Section titled “Boolean Operators”┌─────────────────────────────────────────────────────────────────────┐│ LOGICAL OPERATORS │└─────────────────────────────────────────────────────────────────────┘
┌──────────────────┬──────────────────────────────────────────────────┐│ Operator │ Description │├──────────────────┼──────────────────────────────────────────────────┤│ ! │ NOT (negation) ││ && │ AND ││ || │ OR ││ -a │ AND (in [ ]) ││ -o │ OR (in [ ]) │└──────────────────┴──────────────────────────────────────────────────┘#!/usr/bin/env basha=10b=20
# NOTif [ ! "$a" -eq 10 ]; then echo "a is not 10"else echo "a is 10"fi
# AND - multiple conditions must be trueif [ "$a" -gt 5 ] && [ "$a" -lt 15 ]; then echo "a is between 5 and 15"fi
# OR - at least one condition must be trueif [ "$a" -eq 10 ] || [ "$b" -eq 10 ]; then echo "At least one equals 10"fi
# Using -a and -o in single bracketsif [ "$a" -gt 5 -a "$a" -lt 15 ]; then echo "a is between 5 and 15 (using -a)"fi
# Using [[ ]] with && and || (preferred)if [[ "$a" -gt 5 && "$a" -lt 15 ]]; then echo "a is between 5 and 15 (using [[ ]])"fiNegation Examples
Section titled “Negation Examples”#!/usr/bin/env bash# Negate file testif [ ! -f "/etc/passwd" ]; then echo "File does not exist"else echo "File exists"fi
# Negate string testname=""if [ ! -n "$name" ]; then echo "Name is empty"fi
# Negate command successif ! grep -q "pattern" file.txt; then echo "Pattern not found"fiFile Test Operators
Section titled “File Test Operators”File Existence and Type
Section titled “File Existence and Type”┌─────────────────────────────────────────────────────────────────────┐│ FILE TEST OPERATORS │└─────────────────────────────────────────────────────────────────────┘
┌──────────────────┬──────────────────────────────────────────────────┐│ Operator │ Description │├──────────────────┼──────────────────────────────────────────────────┤│ -e │ File exists ││ -f │ Regular file (not directory/device) ││ -d │ Directory exists ││ -b │ Block device ││ -c │ Character device ││ -p │ Named pipe (FIFO) ││ -S │ Socket ││ -L or -l │ Symbolic link ││ -s │ File exists and is non-empty │└──────────────────┴──────────────────────────────────────────────────┘#!/usr/bin/env bashfile="/etc/passwd"dir="/tmp"
# Check if file existsif [ -e "$file" ]; then echo "File exists"fi
# Check if regular fileif [ -f "$file" ]; then echo "$file is a regular file"fi
# Check if directoryif [ -d "$dir" ]; then echo "$dir is a directory"fi
# Check if symbolic linklink="/usr/bin/python"if [ -L "$link" ]; then echo "$link is a symbolic link"fi
# Check if file is non-emptyif [ -s "$file" ]; then echo "$file exists and is not empty"fiFile Permissions
Section titled “File Permissions”┌─────────────────────────────────────────────────────────────────────┐│ FILE PERMISSION OPERATORS │└─────────────────────────────────────────────────────────────────────┘
┌──────────────────┬──────────────────────────────────────────────────┐│ Operator │ Description │├──────────────────┼──────────────────────────────────────────────────┤│ -r │ File is readable ││ -w │ File is writable ││ -x │ File is executable ││ -O │ Current user owns the file ││ -G │ File group matches current user's group ││ -u │ File has setuid bit set ││ -g │ File has setgid bit set ││ -k │ File has sticky bit set │└──────────────────┴──────────────────────────────────────────────────┘#!/usr/bin/env bashfile="/tmp/test.txt"
# Check if readableif [ -r "$file" ]; then echo "File is readable"fi
# Check if writableif [ -w "$file" ]; then echo "File is writable"fi
# Check if executableif [ -x "$file" ]; then echo "File is executable"fi
# Combined permission checkif [ -r "$file" ] && [ -w "$file" ]; then echo "File has read and write permissions"fi
# Check ownershipif [ -O "$file" ]; then echo "You own this file"fiFile Comparison
Section titled “File Comparison”┌─────────────────────────────────────────────────────────────────────┐│ FILE COMPARISON OPERATORS │└─────────────────────────────────────────────────────────────────────┘
┌──────────────────┬──────────────────────────────────────────────────┐│ Operator │ Description │├──────────────────┼──────────────────────────────────────────────────┤│ -nt │ File1 is newer than File2 ││ -ot │ File1 is older than File2 ││ -ef │ File1 and File2 are the same file (same inode) │└──────────────────┴──────────────────────────────────────────────────┘#!/usr/bin/env bashfile1="/tmp/file1.txt"file2="/tmp/file2.txt"
# Check if file1 is newerif [ "$file1" -nt "$file2" ]; then echo "$file1 is newer than $file2"fi
# Check if file1 is olderif [ "$file1" -ot "$file2" ]; then echo "$file1 is older than $file2"fi
# Check if same file (same inode)if [ "$file1" -ef "$file2" ]; then echo "$file1 and $file2 are the same file"fiCompound Operators
Section titled “Compound Operators”Using Parentheses
Section titled “Using Parentheses”#!/usr/bin/env basha=10b=20
# Grouping conditionsif [ \( "$a" -gt 5 \) -a \( "$a" -lt 20 \) ]; then echo "a is between 5 and 20"fi
# Or use [[ ]] which doesn't need escapingif [[ "$a" -gt 5 && "$a" -lt 20 ]]; then echo "a is between 5 and 20 (cleaner syntax)"fi
# Using ( ) for subshell( cd /tmp echo "In subshell, pwd: $(pwd)")echo "Back to main, pwd: $(pwd)"
# Using { } for grouping (in current shell){ cd /tmp echo "In group, pwd: $(pwd)"}echo "After group, pwd: $(pwd)"Ternary-like Operator
Section titled “Ternary-like Operator”#!/usr/bin/env bash# Using arithmetic expansion for ternary-like behaviora=10
# Condition ? true_value : false_valueresult=$(( a > 5 ? "greater" : "smaller" ))echo "Result: $result"
# More practicalstatus="running"message=$([ "$status" = "running" ] && echo "All good!" || echo "Issues!")echo "$message"
# With variablesa=15b=10max=$(( a > b ? a : b ))min=$(( a < b ? a : b ))echo "Max: $max, Min: $min"Real-World Examples
Section titled “Real-World Examples”Example 1: System Health Check
Section titled “Example 1: System Health Check”#!/usr/bin/env bashset -euo pipefail
# ThresholdsCPU_THRESHOLD=80MEMORY_THRESHOLD=85DISK_THRESHOLD=90
# Check CPU usagecpu_usage=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)cpu_usage_int=${cpu_usage%.*} # Remove decimal
if [ "$cpu_usage_int" -gt "$CPU_THRESHOLD" ]; then echo "WARNING: High CPU usage: ${cpu_usage}%"else echo "OK: CPU usage is ${cpu_usage}%"fi
# Check memory usagemem_usage=$(free | grep Mem | awk '{printf "%.0f", $3/$2 * 100.0}')
if [ "$mem_usage" -gt "$MEMORY_THRESHOLD" ]; then echo "WARNING: High memory usage: ${mem_usage}%"else echo "OK: Memory usage is ${mem_usage}%"fi
# Check disk usagedisk_usage=$(df -h / | tail -1 | awk '{print $5}' | tr -d '%')
if [ "$disk_usage" -gt "$DISK_THRESHOLD" ]; then echo "WARNING: High disk usage: ${disk_usage}%"else echo "OK: Disk usage is ${disk_usage}%"fiExample 2: Service Status Check
Section titled “Example 2: Service Status Check”#!/usr/bin/env bashSERVICE="nginx"
# Check if service is runningif systemctl is-active --quiet "$SERVICE"; then echo "$SERVICE is running"else echo "$SERVICE is NOT running" exit 1fi
# Check if service is enabledif systemctl is-enabled --quiet "$SERVICE"; then echo "$SERVICE is enabled at boot"else echo "$SERVICE is NOT enabled at boot"fiExample 3: Version Comparison
Section titled “Example 3: Version Comparison”#!/usr/bin/env bash# Function to compare versions# Returns 0 if v1 > v2, 1 if v1 < v2, 2 if equalversion_compare() { if [ "$1" = "$2" ]; then return 2 fi
local IFS=. local i ver1=($1) ver2=($2)
for ((i=${#ver1[@]}; i<${#ver2[@]}; i++)); do ver1[i]=0 done
for ((i=0; i<${#ver1[@]}; i++)); do if [[ -z "${ver2[i]}" ]]; then ver2[i]=0 fi if ((10#${ver1[i]} > 10#${ver2[i]})); then return 0 fi if ((10#${ver1[i]} < 10#${ver2[i]})); then return 1 fi done}
# Testv1="1.2.3"v2="1.2.10"
version_compare "$v1" "$v2"result=$?
if [ $result -eq 0 ]; then echo "$v1 > $v2"elif [ $result -eq 1 ]; then echo "$v1 < $v2"else echo "$v1 == $v2"fiExample 4: Input Validation
Section titled “Example 4: Input Validation”#!/usr/bin/env bash# Validate that input is a numberis_number() { local re='^[0-9]+$' [[ "$1" =~ $re ]]}
# Validate IP addressis_ip() { local re='^([0-9]{1,3}\.){3}[0-9]{1,3}$' [[ "$1" =~ $re ]]}
# Validate port numberis_port() { [[ "$1" =~ ^[0-9]+$ ]] && [ "$1" -ge 1 ] && [ "$1" -le 65535 ]}
# Usageinput="8080"
if is_number "$input"; then echo "Valid number: $input"else echo "Not a number"fi
if is_port "$input"; then echo "Valid port: $input"else echo "Invalid port"fiOperator Precedence
Section titled “Operator Precedence”┌─────────────────────────────────────────────────────────────────────┐│ OPERATOR PRECEDENCE (High to Low) │└─────────────────────────────────────────────────────────────────────┘
┌──────────────────┬──────────────────────────────────────────────────┐│ Precedence │ Operators │├──────────────────┼──────────────────────────────────────────────────┤│ Highest │ ( ), !, - (unary), ~, ++, -- ││ │ *, /, % ││ │ +, - ││ │ <<, >> ││ │ <, <=, >, >= ││ │ ==, != ││ │ & (bitwise) ││ │ ^ (bitwise XOR) ││ │ | (bitwise OR) ││ │ && ││ Lowest │ || │└──────────────────┴──────────────────────────────────────────────────┘#!/usr/bin/env bash# Demonstrating precedence# * and / have higher precedence than + and -
result=$(( 2 + 3 * 4 )) # 14, not 20echo "2 + 3 * 4 = $result"
result=$(( (2 + 3) * 4 )) # 20echo "(2 + 3) * 4 = $result"
# Logical operatorsresult=$(( 1 && 0 )) # 0 (AND)echo "1 && 0 = $result"
result=$(( 1 || 0 )) # 1 (OR)echo "1 || 0 = $result"
result=$(( ! 0 )) # 1 (NOT)echo "! 0 = $result"Summary
Section titled “Summary”In this chapter, you learned about:
- ✅ Arithmetic operators (+, -, *, /, %, etc.)
- ✅ Increment and decrement operators
- ✅ Bitwise operators
- ✅ Numeric comparison operators (-eq, -ne, -lt, etc.)
- ✅ String comparison operators (=, !=, <, >, -z, -n)
- ✅ Logical operators (!, &&, ||, -a, -o)
- ✅ File test operators (-f, -d, -r, -w, -x, etc.)
- ✅ File permission operators
- ✅ File comparison operators (-nt, -ot, -ef)
- ✅ Compound operators
- ✅ Operator precedence
- ✅ Practical examples for DevOps
Exercises
Section titled “Exercises”Level 1: Basics
Section titled “Level 1: Basics”- Write a calculator script using arithmetic operators
- Create a script that compares two numbers
- Write a script that checks file permissions
Level 2: Intermediate
Section titled “Level 2: Intermediate”- Implement a version comparison function
- Create a script that validates IP addresses and ports
- Write a script that checks multiple system health metrics
Level 3: Advanced
Section titled “Level 3: Advanced”- Implement a complete input validation library
- Create a script that uses bitwise operators for flags
- Write a complex conditional expression parser
Next Steps
Section titled “Next Steps”Continue to the next chapter to learn about control flow with conditionals.
Previous Chapter: Special Variables Next Chapter: Control Flow - Conditionals