Table of Contents
- Understanding Bash Scripting Basics
- Getting Started with Your First Bash Script
- Key Concepts for Task Automation
- Practical Examples of Automated Tasks
- Advanced Automation Techniques
- Best Practices for Bash Scripting
- Troubleshooting Common Issues
- Conclusion
- 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:$USERis an environment variable with the current username.current_time=$(date ...):$(command)captures the output ofdate(command substitution).uptime=$(uptime | awk ... | sed ...): Pipes (|) chain commands to processuptimeoutput (e.g.,awkextracts uptime,sedremoves 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/tarinstead oftar). - Test Thoroughly: Run scripts with
bash -n script.shto check for syntax errors. - Handle Errors: Use
set -euo pipefailand 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
+xpermission 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
ifstatements (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
- GNU Bash Manual
- Cron How-To (Ubuntu)
- rsync Documentation
- Bash Cookbook (O’Reilly Media)
- ShellCheck (Bash script linter)