thelinuxvault guide

How to Automate Your Daily Linux Tasks with Bash

In the world of Linux, repetitive tasks—whether it’s backing up files, cleaning logs, monitoring system resources, or updating packages—can eat up valuable time. Manually running these tasks daily not only wastes effort but also increases the risk of human error. The solution? **Bash scripting**. Bash (Bourne Again SHell) is the default shell for most Linux distributions, and it’s a powerful tool for automating tasks. With a few lines of code, you can write scripts to handle everything from simple file operations to complex system maintenance. This blog will guide you through the process of automating your daily Linux tasks using Bash, even if you’re new to scripting. By the end, you’ll have the skills to create, test, and schedule scripts that save you time and streamline your workflow.

Table of Contents

  1. Understanding Bash Scripting Basics
  2. Getting Started with Your First Bash Script
  3. Key Concepts for Task Automation
  4. Practical Examples of Automated Tasks
  5. Advanced Automation Techniques
  6. Best Practices for Bash Scripting
  7. Troubleshooting Common Issues
  8. Conclusion
  9. References

Understanding Bash Scripting Basics

Before diving into automation, let’s cover the fundamentals of Bash scripting. A Bash script is a text file containing a sequence of commands that the Bash shell can execute. Think of it as a recipe: it tells the shell what to do and how to do it.

1.1 The Shebang Line

Every Bash script starts with a shebang line (#!/bin/bash), which tells the system to use the Bash interpreter to run the script. Without this line, the system might use a different shell (e.g., sh), leading to unexpected behavior.

Example:

#!/bin/bash

1.2 Execution Permissions

To run a script, you need to make it executable using the chmod command. The +x flag grants execute permission:

chmod +x my_script.sh

Now you can run the script with:

./my_script.sh  # If in the same directory
# OR
/path/to/my_script.sh  # Full path

1.3 Variables

Variables store data for reuse. In Bash, you define variables without spaces around the = sign. Use $variable_name to access their values.

Example:

#!/bin/bash
name="Alice"
echo "Hello, $name!"  # Output: Hello, Alice!

Quotes preserve spaces in variables. Use double quotes (" ") for variable expansion or single quotes (' ') for literal strings:

greeting="Hello, $name!"  # Expands $name: "Hello, Alice!"
literal='Hello, $name!'   # Treated as text: "Hello, $name!"

1.4 Basic Commands

Bash scripts leverage Linux commands you already know (e.g., echo, ls, cp). Combine them to build logic:

  • echo "text": Print text to the terminal.
  • read variable: Get input from the user.
  • if-else: Conditional logic (e.g., “if file exists, do X; else do Y”).
  • for/while loops: Repeat actions (e.g., “process all .txt files in a directory”).

Getting Started with Your First Bash Script

Let’s create a simple script to greet the user and display system information. This will reinforce the basics.

Step 1: Create the Script File

Open a text editor (e.g., nano, vim) and create system_greeter.sh:

nano system_greeter.sh

Step 2: Write the Script

Add the following code:

#!/bin/bash

# System Greeter: Greets the user and shows basic system info

# Get current user (using $USER environment variable)
user=$USER

# Get current date and time
current_time=$(date "+%A, %B %d, %Y %H:%M:%S")

# Get system uptime (using the uptime command)
uptime=$(uptime | awk '{print $3 " " $4}' | sed 's/,//')

# Greet the user
echo "======================================"
echo "Welcome back, $user!"
echo "Current time: $current_time"
echo "System uptime: $uptime"
echo "======================================"

Step 3: Make It Executable and Run

chmod +x system_greeter.sh
./system_greeter.sh

Output might look like:

======================================
Welcome back, alice!
Current time: Wednesday, October 05, 2023 14:30:45
System uptime: 2 days
======================================

Step 4: Breakdown

  • #: Comments (explain the script for readability).
  • user=$USER: $USER is an environment variable with the current username.
  • current_time=$(date ...): $(command) captures the output of date (command substitution).
  • uptime=$(uptime | awk ... | sed ...): Pipes (|) chain commands to process uptime output (e.g., awk extracts uptime, sed removes commas).

Key Concepts for Task Automation

To automate effectively, master these core concepts:

3.1 Scheduling with Cron

Cron is a time-based job scheduler that runs scripts at specified intervals (e.g., daily, weekly). Use crontab -e to edit your cron jobs.

Cron Syntax:

* * * * * command_to_run
| | | | |
| | | | +-- Day of the week (0=Sun, 6=Sat)
| | | +---- Month (1-12)
| | +------ Day of the month (1-31)
| +-------- Hour (0-23)
+---------- Minute (0-59)

Examples:

  • 0 8 * * * /path/to/backup.sh: Run daily at 8 AM.
  • 30 17 * * 1-5 /path/to/cleanup.sh: Run weekdays at 5:30 PM.

3.2 Input/Output Redirection

Redirect command output to files instead of the terminal:

  • >: Overwrite a file (e.g., echo "Hi" > output.txt).
  • >>: Append to a file (e.g., echo "Again" >> output.txt).
  • 2>: Redirect errors (e.g., ls non_existent_file 2> error.log).
  • &>: Redirect both output and errors (e.g., script.sh &> script.log).

3.3 Pipes (|)

Chain commands to process data sequentially. For example:

# List all .log files, count lines, sort by line count (descending)
ls -1 *.log | xargs wc -l | sort -nr

3.4 Error Handling

Prevent scripts from failing silently:

  • set -e: Exit the script if any command fails.
  • set -u: Treat undefined variables as errors.
  • trap "command" ERR: Run a command (e.g., cleanup) when an error occurs.

Example:

#!/bin/bash
set -euo pipefail  # Strict error checking

# If "file.txt" doesn't exist, script exits here
cp file.txt backup/

3.5 Functions

Reuse code with functions. Define them with function_name() { ... }:

#!/bin/bash

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

log "Starting backup..."  # Output: [2023-10-05 15:00:00] Starting backup...

Practical Examples of Automated Tasks

Let’s build scripts for common daily tasks.

4.1 Daily Backup Script

Automate backups of important files (e.g., Documents/) to an external drive or cloud.

Script: daily_backup.sh

#!/bin/bash
set -euo pipefail

# Configuration
SOURCE_DIR="$HOME/Documents"
DEST_DIR="/mnt/external_drive/backups"
BACKUP_NAME="docs_backup_$(date +%Y%m%d).tar.gz"  # Add timestamp

# Create backup directory if it doesn't exist
mkdir -p "$DEST_DIR"

# Backup using tar (compress and archive)
echo "Creating backup: $DEST_DIR/$BACKUP_NAME"
tar -czf "$DEST_DIR/$BACKUP_NAME" -C "$SOURCE_DIR" .

# Optional: Delete backups older than 30 days
find "$DEST_DIR" -name "docs_backup_*.tar.gz" -mtime +30 -delete

echo "Backup completed successfully!"

Test It:

chmod +x daily_backup.sh
./daily_backup.sh

Schedule with Cron: Run daily at 2 AM:

crontab -e
# Add: 0 2 * * * /home/alice/daily_backup.sh >> /var/log/backup.log 2>&1

4.2 Log Rotation Script

Prevent log files from consuming too much disk space by compressing old logs and deleting very old ones.

Script: rotate_logs.sh

#!/bin/bash
set -euo pipefail

LOG_DIR="/var/log/my_app"
DAYS_TO_KEEP=7  # Keep compressed logs for 7 days
MAX_UNCOMPRESSED_SIZE=10M  # Compress when log reaches 10MB

# Compress logs larger than MAX_UNCOMPRESSED_SIZE
find "$LOG_DIR" -name "*.log" -size +"$MAX_UNCOMPRESSED_SIZE" -exec gzip {} \;

# Delete compressed logs older than DAYS_TO_KEEP
find "$LOG_DIR" -name "*.log.gz" -mtime +"$DAYS_TO_KEEP" -delete

echo "Log rotation completed."

Explanation:

  • gzip {} \;: Compresses each log file found.
  • -mtime +7: Matches files modified more than 7 days ago.

4.3 Disk Space Monitor with Alert

Notify yourself when disk space runs low (e.g., >85% usage).

Script: disk_alert.sh

#!/bin/bash
set -euo pipefail

THRESHOLD=85  # Alert if usage >85%
ALERT_EMAIL="[email protected]"
PARTITION="/dev/sda1"  # Monitor root partition

# Get disk usage percentage (e.g., "82" for 82%)
USAGE=$(df -h "$PARTITION" | awk 'NR==2 {print $5}' | sed 's/%//')

if [ "$USAGE" -gt "$THRESHOLD" ]; then
  echo "WARNING: Disk space on $PARTITION is at $USAGE%!" | mail -s "Disk Space Alert" "$ALERT_EMAIL"
  # For desktop: notify-send "Disk Space Low!" "Usage: $USAGE%"
fi

Test It:

chmod +x disk_alert.sh
./disk_alert.sh

Schedule with Cron: Run hourly:

crontab -e
# Add: 0 * * * * /home/alice/disk_alert.sh

4.4 System Cleanup Script

Free up disk space by removing unnecessary files (e.g., package caches, old kernels).

Script: system_cleanup.sh

#!/bin/bash
set -euo pipefail

echo "Starting system cleanup..."

# Clean apt cache
sudo apt clean
sudo apt autoremove -y

# Clear thumbnail cache
rm -rf ~/.cache/thumbnails/*

# Empty trash
rm -rf ~/.local/share/Trash/*

echo "Cleanup completed. Free space:"
df -h /

Advanced Automation Techniques

5.1 Command-Line Arguments with getopts

Add flexibility by accepting arguments (e.g., --force, --verbose).

Example: backup_with_args.sh

#!/bin/bash
set -euo pipefail

FORCE=0
VERBOSE=0

# Parse arguments with getopts
while getopts "fv" opt; do
  case $opt in
    f) FORCE=1 ;;  # -f: Force overwrite
    v) VERBOSE=1 ;; # -v: Verbose output
    \?) echo "Invalid option: -$OPTARG" >&2; exit 1 ;;
  esac
done

if [ "$VERBOSE" -eq 1 ]; then
  echo "Verbose mode enabled..."
fi

# Use FORCE flag in backup logic...

Run It:

./backup_with_args.sh -fv  # Force + verbose

5.2 Remote Automation with SSH

Run commands on remote servers via SSH (e.g., backup a remote directory).

Script: remote_backup.sh

#!/bin/bash
set -euo pipefail

REMOTE_USER="[email protected]"
REMOTE_DIR="/var/www/data"
LOCAL_DEST="/home/alice/remote_backups"

# Use scp to copy remote files to local
scp -r "$REMOTE_USER:$REMOTE_DIR" "$LOCAL_DEST/remote_data_$(date +%Y%m%d)"

echo "Remote backup completed."

Best Practices for Bash Scripting

  • Comment Liberally: Explain why not just what the code does.
  • Use Absolute Paths: Avoid relying on $PATH (e.g., /usr/bin/tar instead of tar).
  • Test Thoroughly: Run scripts with bash -n script.sh to check for syntax errors.
  • Handle Errors: Use set -euo pipefail and check command exit codes (if ! command; then ...).
  • Version Control: Store scripts in Git for tracking changes.
  • Avoid Hardcoding: Use variables for paths/settings (easier to update).

Troubleshooting Common Issues

  • Permission Denied: Ensure the script has +x permission and the user has access to target files.
  • Cron Not Running: Check cron service status (sudo systemctl status cron), and use absolute paths in cron commands.
  • Syntax Errors: Missing spaces in if statements (e.g., if [ $var=5 ]if [ $var = 5 ]).
  • Variables Not Expanding: Use double quotes ("$var") instead of single quotes.

Conclusion

Bash scripting transforms repetitive Linux tasks into automated workflows, saving time and reducing errors. Start small (e.g., a backup script), then build up to complex automation with cron, pipes, and error handling. With practice, you’ll master the art of scripting and unlock the full power of Linux automation.

References