thelinuxvault guide

Bashtastic Automations: Transform Your Linux Routine

If you’re a Linux user, chances are you’ve found yourself repeating the same tasks day in and day out: backing up files, cleaning up logs, organizing downloads, or updating system packages. What if you could automate these tedious chores with just a few lines of code? Enter **bash scripting**—the unsung hero of Linux productivity. Bash (Bourne Again SHell) is more than just a command-line interface; it’s a powerful scripting language pre-installed on every Linux system. With bash, you can chain commands, loop through tasks, and conditionally execute actions to build custom automations tailored to your workflow. Whether you’re a developer, sysadmin, or casual user, mastering bash automation can turn hours of manual work into minutes (or even seconds) of setup—freeing you to focus on what matters. In this blog, we’ll demystify bash scripting, walk through practical examples, and share pro tips to help you build robust, time-saving automations. Let’s dive in!

Table of Contents

  1. Why Bash Automation Matters
  2. Bash Basics You Need to Know
  3. Practical Automation Examples
  4. Advanced Bash Tips for Power Users
  5. Best Practices for Maintainable Scripts
  6. Tools to Supercharge Your Bash Scripts
  7. Conclusion
  8. References

Why Bash Automation Matters

Before we write our first script, let’s clarify why bash automation is worth your time:

  • Time Savings: Automate repetitive tasks (e.g., backups, log cleanup) and reclaim hours weekly.
  • Consistency: Scripts execute tasks the same way every time, reducing human error.
  • Accessibility: Bash is pre-installed on Linux/macOS, no extra tools required.
  • Integration: Bash plays well with Linux’s ecosystem (e.g., cron for scheduling, awk/sed for text processing).
  • Skill Building: Learning bash sharpens your command-line fluency—a critical skill for Linux users.

Real-World Scenario: Imagine manually zipping your project folder, moving it to an external drive, and deleting old backups every night. A 5-line bash script + cron can do this automatically while you sleep.

Bash Basics You Need to Know

You don’t need to be a programmer to write bash scripts, but a few fundamentals will go a long way. Let’s cover the essentials:

1. Shebang Line

Every script starts with #!/bin/bash (or #!/bin/sh for POSIX compliance). This tells the system to use bash to run the script.

2. Variables

Store data in variables for reuse:

name="Linux User"
echo "Hello, $name!"  # Output: Hello, Linux User!
  • Use $VAR to access variables; {VAR} for clarity (e.g., ${name}_files).
  • Special variables:
    • $0: Script name.
    • $1, $2...: Command-line arguments (e.g., ./script.sh arg1 arg2$1=arg1).
    • $#: Number of arguments.
    • $?: Exit code of the last command (0 = success, non-zero = error).

3. Loops

Repeat actions with for, while, or until loops:

# For loop: Iterate over files in a directory
for file in ~/Downloads/*.txt; do
  echo "Processing $file"
done

# While loop: Run until condition fails
count=1
while [ $count -le 5 ]; do
  echo "Count: $count"
  count=$((count + 1))  # Increment count
done

4. Conditionals

Execute code based on conditions with if-else or case statements:

# Check if a file exists
file="data.txt"
if [ -f "$file" ]; then
  echo "$file exists!"
else
  echo "$file not found."
fi

# Case statement for multiple conditions
day=$(date +%A)
case $day in
  Monday) echo "Start of the workweek!" ;;
  Friday) echo "Weekend is near!" ;;
  *) echo "Just another day." ;;
esac

5. Executing Commands

Run system commands directly in scripts. Use $() to capture output:

current_time=$(date "+%Y-%m-%d %H:%M:%S")
echo "Script ran at: $current_time"

Practical Automation Examples

Let’s build scripts for common Linux tasks. Each example includes a problem statement, script code, explanation, and usage instructions.

Example 1: Daily File Backup Script

Problem: You want to back up a project folder to an external drive and keep only the last 7 backups.

Script Code (backup_project.sh):

#!/bin/bash

# Configuration
SOURCE_DIR="$HOME/projects/my_app"  # Folder to back up
DEST_DIR="/mnt/external_drive/backups"  # Where to save backups
BACKUP_NAME="my_app_backup_$(date +%Y%m%d).tar.gz"  # Name with timestamp

# Create backup
echo "Creating backup: $BACKUP_NAME..."
tar -czf "$DEST_DIR/$BACKUP_NAME" -C "$SOURCE_DIR" .

# Check if backup succeeded
if [ $? -eq 0 ]; then
  echo "Backup completed!"
else
  echo "ERROR: Backup failed!"
  exit 1
fi

# Delete backups older than 7 days
echo "Cleaning up old backups..."
find "$DEST_DIR" -name "my_app_backup_*.tar.gz" -mtime +7 -delete

echo "Done!"

Explanation:

  • tar -czf: Creates a compressed (z) archive (c) with verbose output (v) and saves to a file (f).
  • -C "$SOURCE_DIR" .: Changes to SOURCE_DIR before archiving to avoid including the full path.
  • $? -eq 0: Checks if the last command (tar) succeeded (exit code 0 = success).
  • find ... -mtime +7 -delete: Deletes files older than 7 days.

How to Use:

  1. Save the script as backup_project.sh.
  2. Make it executable: chmod +x backup_project.sh.
  3. Test it: ./backup_project.sh.
  4. Schedule daily runs with cron:
    • Run crontab -e.
    • Add: 0 2 * * * /home/your_user/backup_project.sh (runs at 2 AM daily).

Example 2: Log Rotation & Cleanup

Problem: Your app’s log file (app.log) grows indefinitely, wasting disk space.

Script Code (rotate_logs.sh):

#!/bin/bash

LOG_FILE="/var/log/my_app/app.log"
MAX_SIZE=10M  # Rotate when log reaches 10MB
BACKUP_DIR="/var/log/my_app/old_logs"

# Create backup dir if it doesn't exist
mkdir -p "$BACKUP_DIR"

# Check log size
if [ $(du -b "$LOG_FILE" | cut -f1) -ge $(numfmt --from=iec "$MAX_SIZE") ]; then
  echo "Log file too large. Rotating..."
  
  # Rename current log to app.log.YYYYMMDD
  mv "$LOG_FILE" "$BACKUP_DIR/app.log_$(date +%Y%m%d)"
  
  # Compress the rotated log
  gzip "$BACKUP_DIR/app.log_$(date +%Y%m%d)"
  
  # Create a new empty log file
  touch "$LOG_FILE"
  
  # Set permissions (match original log)
  chmod --reference="$BACKUP_DIR/app.log_$(date +%Y%m%d).gz" "$LOG_FILE"
  
  echo "Log rotated successfully."
else
  echo "Log size is under $MAX_SIZE. No rotation needed."
fi

How to Use:

  • Run manually: ./rotate_logs.sh.
  • For hourly checks, add to cron: 0 * * * * /path/to/rotate_logs.sh.

Example 3: System Cleanup Utility

Problem: Free up disk space by deleting temp files, clearing apt cache, and removing unused packages.

Script Code (system_cleanup.sh):

#!/bin/bash

echo "=== Starting System Cleanup ==="

# Delete user temp files (older than 7 days)
echo "Cleaning user temp files..."
rm -rf ~/.cache/* ~/.local/share/Trash/files/* 2>/dev/null

# Clear apt cache (requires sudo)
echo "Clearing apt cache..."
sudo apt clean

# Remove unused packages (autoremove)
echo "Removing unused packages..."
sudo apt autoremove -y

# Clean system temp files (older than 7 days)
echo "Cleaning system temp files..."
sudo find /tmp -type f -mtime +7 -delete

echo "=== Cleanup Complete ==="

Note: Test with echo first (e.g., echo rm -rf ~/.cache/*) to avoid accidental deletions!

Example 4: Automated File Organizer

Problem: Your Downloads folder is a mess—images, PDFs, and zip files are all mixed.

Script Code (organize_downloads.sh):

#!/bin/bash

DOWNLOADS_DIR="$HOME/Downloads"

# Create folders if missing
mkdir -p "$DOWNLOADS_DIR/{Images,PDFs,Zips,Docs,Other}"

# Move files by extension
echo "Organizing Downloads..."

# Images (jpg, png, jpeg, gif)
find "$DOWNLOADS_DIR" -maxdepth 1 -type f \( -iname "*.jpg" -o -iname "*.png" -o -iname "*.jpeg" -o -iname "*.gif" \) -exec mv {} "$DOWNLOADS_DIR/Images/" \;

# PDFs
find "$DOWNLOADS_DIR" -maxdepth 1 -type f -iname "*.pdf" -exec mv {} "$DOWNLOADS_DIR/PDFs/" \;

# Zips/Archives
find "$DOWNLOADS_DIR" -maxdepth 1 -type f \( -iname "*.zip" -o -iname "*.tar.gz" -o -iname "*.7z" \) -exec mv {} "$DOWNLOADS_DIR/Zips/" \;

# Documents (docx, doc, txt, md)
find "$DOWNLOADS_DIR" -maxdepth 1 -type f \( -iname "*.docx" -o -iname "*.doc" -o -iname "*.txt" -o -iname "*.md" \) -exec mv {} "$DOWNLOADS_DIR/Docs/" \;

# Everything else
find "$DOWNLOADS_DIR" -maxdepth 1 -type f ! -iname "organize_downloads.sh" -exec mv {} "$DOWNLOADS_DIR/Other/" \;

echo "Downloads organized!"

Pro Tip: Run this on login by adding it to your .bashrc or .profile:

# Add to ~/.bashrc
if [ -f "$HOME/organize_downloads.sh" ]; then
  "$HOME/organize_downloads.sh"
fi

Example 5: Custom System Monitoring

Problem: You want a quick overview of CPU, memory, and disk usage.

Script Code (system_monitor.sh):

#!/bin/bash

echo "=== System Monitor ==="
echo "CPU Usage: $(top -bn1 | grep "Cpu(s)" | awk '{print $2 + $4}')%"
echo "Memory Usage: $(free -h | awk '/Mem:/ {print $3 "/" $2 " (" $3/$2*100 "%)"}')"
echo "Disk Usage: $(df -h / | awk '/\// {print $3 "/" $2 " (" $5 ")"}')"
echo "=== End ==="

Output:

=== System Monitor ===
CPU Usage: 12.5%
Memory Usage: 2.3G/7.7G (29.87%)
Disk Usage: 45G/237G (19%)
=== End ===

Advanced Bash Tips for Power Users

Once you’re comfortable with basics, these tips will level up your scripts:

1. Use Functions to Avoid Repetition

Group reusable code into functions:

#!/bin/bash

# Function to log messages
log() {
  echo "[$(date +%Y%m%d %H:%M:%S)] $1"
}

log "Starting backup..."  # Usage: log "message"

2. Error Handling with set -euo pipefail

Make scripts exit on errors and undefined variables:

#!/bin/bash
set -euo pipefail  # Exit on error, undefined var, or failed pipe

# Script will exit if $UNDEFINED_VAR is used (undefined)
echo "$UNDEFINED_VAR"  # Fails here!

3. Parse Arguments with getopts

Handle flags (e.g., ./script.sh -v -o output.txt) cleanly:

#!/bin/bash

verbose=0
output_file="output.txt"

# Parse flags: -v (verbose), -o <file> (output)
while getopts "vo:" opt; do
  case $opt in
    v) verbose=1 ;;
    o) output_file="$OPTARG" ;;
    \?) echo "Invalid option: -$OPTARG" >&2; exit 1 ;;
  esac
done

if [ $verbose -eq 1 ]; then
  echo "Verbose mode enabled. Outputting to $output_file..."
fi

4. Debugging with set -x

Add set -x to trace execution (shows each command before running):

#!/bin/bash
set -x  # Enable debugging
echo "This line will be traced..."
set +x  # Disable debugging
echo "This line won't."

Best Practices for Maintainable Scripts

Write scripts that are easy to read, test, and update:

  • Comment Liberally: Explain why (not just what) the code does.
  • Version Control: Track scripts in Git (e.g., a bash_scripts repo).
  • Test Thoroughly: Use echo to preview commands before running with rm/mv.
  • Secure Sensitive Data: Avoid hardcoding passwords. Use environment variables:
    # Load from .env file (chmod 600 .env to secure)
    source "$HOME/.env"
    echo "API Key: $MY_SECURE_API_KEY"  # From .env
  • Sanitize Inputs: Validate user input to prevent injection attacks:
    read -p "Enter a filename: " filename
    if [[ ! "$filename" =~ ^[a-zA-Z0-9_.-]+$ ]]; then
      echo "Invalid filename!"
      exit 1
    fi

Tools to Enhance Bash

These tools will make scripting faster and scripts more reliable:

  • ShellCheck: Lints scripts for errors (e.g., undefined variables).
    • Install: sudo apt install shellcheck.
    • Use: shellcheck my_script.sh.
  • shfmt: Formats scripts for consistency (like Prettier for bash).
    • Install: sudo apt install shfmt.
    • Use: shfmt -w my_script.sh (auto-fix).
  • fzf: Fuzzy finder for interactive scripts (e.g., select files to process).
  • tput: Add color/style to output (e.g., tput setaf 2 for green text).

Conclusion

Bash automation is a superpower for Linux users. By starting small (e.g., a backup script) and gradually adding complexity, you’ll transform tedious routines into effortless, reliable workflows. Remember: the best script is one that solves your problem—so adapt examples to fit your needs!

What automations will you build first? Share your scripts in the comments below!

References