Picture this: You’re manually checking 50 servers every morning, typing the same health check commands over and over. Meanwhile, your colleague sips coffee while their script automatically checks everything and only alerts when there’s actually a problem. The difference? They’ve mastered conditionals and loops — the brain and muscles of smart automation.
Think of conditionals as your script’s decision-making power and loops as its ability to work tirelessly without getting bored. Together, they transform your simple command sequences into intelligent automation that adapts, repeats, and handles complex scenarios like a seasoned pro.
Why Should You Care About Smart Control Flow?
🚀 Immediate Benefits:
- Automate repetitive tasks across hundreds of items instantly
- Create scripts that make smart decisions based on real conditions
- Handle errors gracefully instead of crashing dramatically
- Build professional automation that colleagues actually trust
- Save hours daily on mundane, repetitive work
Conditional Statements: Teaching Your Scripts to Think
Conditionals are like having a smart assistant who can evaluate situations and make decisions. No more “run this command and pray it works” — your scripts will actually think before they act!
If-Else: Your Basic Decision Maker
# Basic if statement
if [ -f "important.txt" ]; then
echo "✅ Important file found!"
cp important.txt backup/
else
echo "❌ Important file missing!"
echo "Creating default file..."
touch important.txt
fi
Real-World Conditional Examples That’ll Save Your Bacon
1. Smart Disk Space Monitor:
check_disk_space() {
local threshold=80
local current_usage=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//')
if [ $current_usage -gt $threshold ]; then
echo "🚨 CRITICAL: Disk usage at ${current_usage}%!"
echo "🧹 Cleaning up old logs..."
# Clean up automatically
find /var/log -name "*.log" -mtime +7 -delete
find /tmp -name "*" -mtime +1 -delete
echo "✅ Cleanup completed"
elif [ $current_usage -gt 60 ]; then
echo "⚠️ WARNING: Disk usage at ${current_usage}% (getting high)"
else
echo "✅ Disk usage healthy at ${current_usage}%"
fi
}
2. Service Health Check with Auto-Recovery:
check_and_restart_service() {
local service_name=$1
if systemctl is-active --quiet $service_name; then
echo "✅ $service_name is running normally"
else
echo "❌ $service_name is down! Attempting restart..."
if sudo systemctl restart $service_name; then
echo "✅ Successfully restarted $service_name"
# Wait and verify
sleep 5
if systemctl is-active --quiet $service_name; then
echo "🎉 $service_name is healthy after restart"
else
echo "🚨 FAILED: $service_name still not responding!"
echo "📧 Sending alert to admin..."
# Add your alert mechanism here
fi
else
echo "🚨 CRITICAL: Failed to restart $service_name"
fi
fi
}
# Check critical services
check_and_restart_service "nginx"
check_and_restart_service "mysql"
Case Statements: Multiple Choice Made Simple
When you need to handle multiple options, case statements are cleaner than endless if-else chains, here is a example for case statement where we are doing deployment based on the environment var. Which is most common use case.
deploy_application() {
local environment=$1
case $environment in
"dev"|"development")
echo "🔧 Deploying to DEVELOPMENT environment"
export APP_ENV=development
export DEBUG=true
docker-compose -f docker-compose.dev.yml up -d
;;
"staging"|"stage")
echo "🔍 Deploying to STAGING environment"
export APP_ENV=staging
export DEBUG=false
docker-compose -f docker-compose.staging.yml up -d
;;
"prod"|"production")
echo "🚀 Deploying to PRODUCTION environment"
export APP_ENV=production
export DEBUG=false
# Extra safety check for production
read -p "⚠️ PRODUCTION DEPLOY - Are you sure? (yes/no): " confirm
if [ "$confirm" = "yes" ]; then
docker-compose -f docker-compose.prod.yml up -d
echo "🎉 Production deployment complete!"
else
echo "❌ Production deployment cancelled"
return 1
fi
;;
*)
echo "❌ Error: Unknown environment '$environment'"
echo "Valid options: dev, staging, prod"
return 1
;;
esac
}
# Usage examples:
deploy_application "dev"
deploy_application "production"
Loops: Your Tireless Digital Workers
Loops are like having an army of robots that never get tired, never make mistakes, and can process thousands of items in seconds. Master these, and you’ll never manually repeat tasks again!
For Loops: Process Everything in a List
- Server Maintenance Across Multiple Machines:
Different things like checking if servers are working using a ping command, and updating their libraries and repo by SSH using a automated script instead of logging into different instances.
maintain_servers() {
local servers=("web1.company.com" "web2.company.com" "api.company.com" "db.company.com")
for server in "${servers[@]}"; do
echo "🔄 Maintaining $server..."
# Check if server is reachable
if ping -c 1 $server &>/dev/null; then
echo "✅ $server is reachable"
# Run maintenance commands
ssh user@$server "
sudo apt update
sudo apt autoremove -y
docker system prune -f
systemctl status nginx | head -3
"
echo "✅ Maintenance completed for $server"
else
echo "❌ $server is unreachable!"
fi
echo "---"
done
echo "🎉 All server maintenance completed!"
}
2. Batch File Processing:
process_images() {
local input_dir="./raw_images"
local output_dir="./processed_images"
mkdir -p "$output_dir"
for image in "$input_dir"/*.{jpg,png,jpeg}; do
# Skip if no matching files
[ ! -f "$image" ] && continue
local filename=$(basename "$image")
local name_without_ext="${filename%.*}"
echo "🖼️ Processing $filename..."
# Resize and optimize
convert "$image" -resize 800x600 -quality 85 "$output_dir/${name_without_ext}_resized.jpg"
echo "✅ Created: ${name_without_ext}_resized.jpg"
done
}
While Loops: Keep Going Until Something Changes
1. Wait for Service to be Ready:
wait_for_service() {
local service_url=$1
local timeout=300 # 5 minutes
local elapsed=0
echo "⏳ Waiting for service at $service_url to be ready..."
while [ $elapsed -lt $timeout ]; do
if curl -f -s "$service_url/health" &>/dev/null; then
echo "✅ Service is ready! (took ${elapsed}s)"
return 0
fi
echo "⏳ Still waiting... (${elapsed}s elapsed)"
sleep 10
((elapsed += 10))
done
echo "❌ Service failed to start within ${timeout}s"
return 1
}
# Deploy and wait for readiness
docker-compose up -d
wait_for_service "http://localhost:3000"
2. Monitoring Log Files in Real-Time:
monitor_errors() {
local log_file="/var/log/application.log"
local error_count=0
local max_errors=5
echo "👁️ Monitoring $log_file for errors..."
tail -f "$log_file" | while read line; do
if echo "$line" | grep -i "error" &>/dev/null; then
((error_count++))
echo "🚨 ERROR #$error_count detected: $line"
if [ $error_count -ge $max_errors ]; then
echo "🚨 CRITICAL: $max_errors errors detected!"
echo "🔄 Restarting application..."
sudo systemctl restart myapp
error_count=0
fi
fi
done
}
Until Loops: Keep Trying Until Success
The stubborn code which runs until it gets what it wants in other words runs until it becomes True.
deploy_with_retry() {
local max_attempts=5
local attempt=1
until [ $attempt -gt $max_attempts ]; do
echo "🚀 Deployment attempt $attempt of $max_attempts..."
if ./deploy.sh; then
echo "✅ Deployment successful on attempt $attempt!"
break
else
echo "❌ Deployment failed (attempt $attempt)"
if [ $attempt -eq $max_attempts ]; then
echo "🚨 CRITICAL: All deployment attempts failed!"
return 1
fi
echo "⏳ Waiting 30s before retry..."
sleep 30
fi
((attempt++))
done
}
Combining Conditionals and Loops for Maximum Power
Smart Backup System with Intelligence:
intelligent_backup() {
local source_dirs=("/home/user/documents" "/var/www/html" "/etc/nginx")
local backup_base="/backups"
local success_count=0
local total_size=0
# Check if backup directory exists
if [ ! -d "$backup_base" ]; then
echo "📁 Creating backup directory..."
mkdir -p "$backup_base"
fi
for dir in "${source_dirs[@]}"; do
local dir_name=$(basename "$dir")
local backup_file="$backup_base/${dir_name}_$(date +%Y%m%d_%H%M%S).tar.gz"
echo "📦 Backing up $dir..."
# Check if source exists and has content
if [ ! -d "$dir" ]; then
echo "⚠️ Skipping $dir (doesn't exist)"
continue
fi
if [ -z "$(ls -A $dir)" ]; then
echo "⚠️ Skipping $dir (empty directory)"
continue
fi
# Create backup with progress
if tar -czf "$backup_file" "$dir" 2>/dev/null; then
local size=$(du -h "$backup_file" | cut -f1)
echo "✅ Backup created: $backup_file ($size)"
((success_count++))
# Add to total size (convert to bytes for math)
local size_bytes=$(du -b "$backup_file" | cut -f1)
((total_size += size_bytes))
else
echo "❌ Failed to backup $dir"
fi
done
# Summary report
echo ""
echo "📊 Backup Summary:"
echo " Successful backups: $success_count/${#source_dirs[@]}"
echo " Total backup size: $(numfmt --to=iec $total_size)"
if [ $success_count -eq ${#source_dirs[@]} ]; then
echo "🎉 All backups completed successfully!"
return 0
else
echo "⚠️ Some backups failed - check logs above"
return 1
fi
}
TLDR Cheat Sheet
🔧 Conditional Essentials:
if [ condition ]; then commands; fi
- Basic decision makingelif [ other_condition ]; then
- Multiple conditionscase $var in pattern) commands;; esac
- Multiple choice handling[ $num -gt 10 ]
- Numeric comparisons (-eq, -ne, -lt, -le, -ge)[ "$string" = "value" ]
- String comparisons (=, !=, <, >)
🔧 Loop Essentials:
for item in list; do commands; done
- Process each item in a listfor file in *.txt; do
- Process files matching patternwhile [ condition ]; do commands; done
- Repeat while condition is trueuntil [ condition ]; do commands; done
- Repeat until condition becomes truebreak
- Exit loop early,continue
- Skip to next iteration
🔧 Pro Tips:
- Always quote variables:
[ "$var" = "value" ]
- Use
[[ ]]
for advanced features like regex:[[ $var =~ ^[0-9]+$ ]]
- Test conditions first:
echo "Testing: [ $disk_usage -gt 80 ]"
- Handle empty loops:
[ ! -f "$file" ] && continue