Bash Script To Run Commands

Bash Script To Run Commands

Reading time1 min
#Automation#Linux#Bash#Scripting#Shell

Mastering Bash Scripts to Automate Complex Command Sequences with Conditional Logic

Most guides show you how to run commands sequentially in bash scripts, but few reveal how to embed intelligent decision-making directly in your scripts—turning simple automation into a dynamic tool that adapts to real-world conditions.

If you spend time managing servers or developing software, you know how repetitive command sequences can become. Automating these with bash scripts not only saves time but also minimizes costly human errors. However, basic automation—just running commands one after another—is only half the story. By incorporating conditional logic into your bash scripts, you can create smarter automation pipelines that respond appropriately depending on the circumstances, making your workflows more efficient and reliable.

In this post, we’ll explore practical techniques for mastering conditional statements and control flow in bash scripting. You’ll learn how to craft scripts that run complex command sequences intelligently based on real-time conditions encountered during execution.


Why Use Conditional Logic in Bash Scripts?

Imagine you have a backup script that copies critical files but only if the destination directory is available and has enough free space. Or a deployment script that checks if the previous step was successful before continuing.

Without conditional logic, you'd have to manually check for these conditions or risk your scripts blindly failing or corrupting data.

By harnessing conditional constructs like if, case, and logical operators (&&, ||), your scripts can:

  • Make decisions based on command success/failure
  • Inspect file contents, system properties, environment variables
  • Repeat tasks dynamically until certain conditions are met
  • Handle errors gracefully and take corrective actions

Basic Conditional Statements in Bash

The if statement

At its core, conditional scripting begins with if. Here’s an example that checks if a directory exists before copying files:

#!/bin/bash

BACKUP_DIR="/mnt/backup"
SOURCE_DIR="/home/user/data"

if [ -d "$BACKUP_DIR" ]; then
  echo "Backup directory exists. Proceeding with copy..."
  cp -r "$SOURCE_DIR"/* "$BACKUP_DIR"/
  echo "Backup completed successfully."
else
  echo "Error: Backup directory does not exist."
  exit 1
fi
  • The expression [ -d "$BACKUP_DIR" ] tests if $BACKUP_DIR is a directory.
  • If true, the script copies source files.
  • Otherwise, it exits with an error code.

Testing Command Success with if

Commands return exit codes, where zero means success and any other number indicates failure. You can use this to decide what happens next:

#!/bin/bash

systemctl start nginx

if [ $? -eq 0 ]; then
  echo "Nginx started successfully."
else
  echo "Failed to start Nginx. Check configuration."
fi

Alternatively (and more readably), you can use the command directly in the if condition:

#!/bin/bash

if systemctl start nginx; then
  echo "Nginx started successfully."
else
  echo "Failed to start Nginx."
fi

Here, bash executes systemctl start nginx. If it returns zero (success), the first branch runs; otherwise the second.


Using Logical Operators for Complex Conditions

Sometimes you want multiple checks combined.

  • AND operator: &&
  • OR operator: ||

Example: proceed only if both a file exists and is writable:

FILE="/etc/myapp/config.yaml"

if [ -f "$FILE" ] && [ -w "$FILE" ]; then
  echo "$FILE exists and is writable"
else
  echo "Cannot write to $FILE"
fi

Or try one action and fallback to another:

mkdir /backup/data || mkdir ~/backup/data && echo "Backup directory created"

Here, it tries /backup/data first; if that fails (because of permissions), it creates the directory under your home folder instead.


Using case for Multiple Options

When multiple distinct possibilities exist, case can simplify code readability.

#!/bin/bash

read -p "Enter environment (dev/staging/prod): " ENV

case $ENV in 
  dev)
    echo "Deploying to Development server"
    # run dev deployment commands here 
    ;;
    
  staging)
    echo "Deploying to Staging server"
    # run staging deployment commands here 
    ;;
    
  prod)
    echo "Deploying to Production server"
    # run production deployment commands here 
    ;;
    
  *)
    echo "Unknown environment: $ENV"
    exit 1 
    ;;
esac

This structure easily scales with many options and keeps things organized.


Loops Combined With Conditionals for Dynamic Automation

Suppose you want to monitor a service restart and retry several times with delays:

#!/bin/bash

MAX_RETRIES=5
COUNT=0

until systemctl restart myservice; do
  ((COUNT++))
  if [ $COUNT -ge $MAX_RETRIES ]; then
    echo "Failed to restart myservice after $MAX_RETRIES attempts."
    exit 1
  fi
  
  echo "Retry $COUNT/$MAX_RETRIES failed. Retrying in 10 seconds..."
  sleep 10
done

echo "myservice restarted successfully."

Here we combine loops (until) with conditionals (if) for robust retry logic.


Putting It All Together: A Smart Backup Script Example

#!/bin/bash

SOURCE="/var/www/html"
DEST="/mnt/backup/html_backup"
LOGFILE="/var/log/backup.log"

echo "$(date): Starting backup..." >> "$LOGFILE"

# Check destination availability and free space (>1GB)
if mountpoint -q "/mnt/backup"; then
  
  AVAILABLE_SPACE=$(df --output=avail /mnt/backup | tail -1)
  
  # Convert available space from KB; require at least ~1GB = ~1,000,000KB  
  if [ "$AVAILABLE_SPACE" -gt 1000000 ]; then
    
    cp -r "$SOURCE"/* "$DEST"/ && \
      echo "$(date): Backup succeeded." >> "$LOGFILE" || \
      { echo "$(date): Backup failed!" >> "$LOGFILE"; exit 1; }
      
  else  
    echo "$(date): Not enough space on backup drive." >> "$LOGFILE"
    exit 2  
  fi
  
else
  
  echo "$(date): Backup mount point not available." >> "$LOGFILE"
  
fi

echo "$(date): Backup script finished." >> "$LOGFILE"

This fully automated backup script:

  • Checks if the backup drive is mounted using mountpoint
  • Verifies available free space using df
  • Runs copy operation only if conditions are good
  • Logs all status messages for audit trails
  • Exits with status codes indicating success or reasons for failure

Final Tips for Writing Conditional Bash Scripts

  • Use [ ... ] or [[ ... ]] tests carefully—note differences in syntax support among shells.
  • Quote variables inside tests ([ -f "$VAR" ]) to avoid word-splitting bugs.
  • Return meaningful exit codes (0 = success) from your scripts so other tools or cron jobs can react appropriately.
  • Comment generously — conditional logic paths get complex quickly.
  • Test each branch manually during development before deploying wide-scale automation.

Conclusion

Mastering conditional logic in bash scripting transforms static command sequences into smart automation workflows that dynamically respond to your system’s state—minimizing errors and maximizing efficiency.

By practicing these patterns—if, case, logical operators, loops—you’ll be equipped to build flexible deployment scripts, monitoring tools, batch jobs, and more that adapt intelligently without manual intervention.

So next time you write a bash automation script, ask yourself: “What decisions should my script make along the way?” Then start embedding those decisions right inside—your future self will thank you!

Happy scripting! 🚀