Automation5 min read475 lines

Learning state

Track this guide

Saved in this browser only. No account required.

Shell Scripting (Bash) Master Class

Engineering-Grade Reference Manual for Bash Scripting
A comprehensive guide to shell scripting automation and best practices


Table of Contents

  1. Bash Fundamentals
  2. Variables & Data Types
  3. Control Structures
  4. Functions
  5. Arrays
  6. String Manipulation
  7. File Operations
  8. Process Management
  9. Error Handling
  10. Best Practices

Bash Fundamentals

๐Ÿ”น Shebang and Script Basics

#!/bin/bash
# This is a comment

# Make script executable
chmod +x script.sh

# Run script
./script.sh

# Run with bash explicitly
bash script.sh

๐Ÿ”น Variables

# Variable assignment (no spaces around =)
NAME="John"
AGE=30

# Using variables
echo "Name: $NAME"
echo "Age: ${AGE}"

# Command substitution
CURRENT_DATE=$(date +%Y-%m-%d)
FILES=$(ls -1)

# Read user input
read -p "Enter your name: " USERNAME
echo "Hello, $USERNAME"

# Environment variables
export PATH="/usr/local/bin:$PATH"
echo $HOME
echo $USER

Variables & Data Types

๐Ÿ”น Special Variables

$0  # Script name
$1, $2, $3  # Positional parameters
$#  # Number of arguments
$@  # All arguments as separate words
$*  # All arguments as single word
$?  # Exit status of last command
$$  # Process ID of script
$!  # Process ID of last background command

๐Ÿ”น Variable Operations

# Default values
echo "${VAR:-default}"  # Use default if VAR is unset
echo "${VAR:=default}"  # Set and use default if VAR is unset
echo "${VAR:?error}"    # Error if VAR is unset

# String length
NAME="John"
echo "${#NAME}"  # 4

# Arithmetic
NUM=10
((NUM++))
echo $((NUM + 5))

# Let command
let "result = 5 + 3"

Control Structures

๐Ÿ”น If Statements

# Basic if
if [ "$NAME" = "John" ]; then
    echo "Hello John"
fi

# If-else
if [ $AGE -gt 18 ]; then
    echo "Adult"
else
    echo "Minor"
fi

# If-elif-else
if [ $SCORE -ge 90 ]; then
    echo "A"
elif [ $SCORE -ge 80 ]; then
    echo "B"
else
    echo "C"
fi

# Multiple conditions
if [ $AGE -gt 18 ] && [ "$NAME" = "John" ]; then
    echo "Adult named John"
fi

# File tests
if [ -f "file.txt" ]; then
    echo "File exists"
fi

if [ -d "directory" ]; then
    echo "Directory exists"
fi

if [ -r "file.txt" ]; then
    echo "File is readable"
fi

๐Ÿ”น Case Statements

case "$1" in
    start)
        echo "Starting service..."
        ;;
    stop)
        echo "Stopping service..."
        ;;
    restart)
        echo "Restarting service..."
        ;;
    *)
        echo "Usage: $0 {start|stop|restart}"
        exit 1
        ;;
esac

๐Ÿ”น Loops

# For loop
for i in 1 2 3 4 5; do
    echo "Number: $i"
done

# For loop with range
for i in {1..10}; do
    echo $i
done

# For loop with files
for file in *.txt; do
    echo "Processing $file"
done

# While loop
COUNT=0
while [ $COUNT -lt 5 ]; do
    echo "Count: $COUNT"
    ((COUNT++))
done

# Until loop
COUNT=0
until [ $COUNT -ge 5 ]; do
    echo "Count: $COUNT"
    ((COUNT++))
done

# Read file line by line
while IFS= read -r line; do
    echo "Line: $line"
done < file.txt

Functions

๐Ÿ”น Function Basics

# Define function
function greet() {
    echo "Hello, $1!"
}

# Call function
greet "John"

# Function with return value
function add() {
    local result=$(($1 + $2))
    echo $result
}

SUM=$(add 5 3)
echo "Sum: $SUM"

# Function with return code
function check_file() {
    if [ -f "$1" ]; then
        return 0
    else
        return 1
    fi
}

if check_file "test.txt"; then
    echo "File exists"
fi

Arrays

๐Ÿ”น Array Operations

# Declare array
FRUITS=("apple" "banana" "orange")

# Access elements
echo "${FRUITS[0]}"  # apple
echo "${FRUITS[@]}"  # all elements
echo "${#FRUITS[@]}" # array length

# Add element
FRUITS+=("grape")

# Loop through array
for fruit in "${FRUITS[@]}"; do
    echo "Fruit: $fruit"
done

# Associative arrays (Bash 4+)
declare -A COLORS
COLORS[red]="#FF0000"
COLORS[green]="#00FF00"

echo "${COLORS[red]}"

# Loop through associative array
for key in "${!COLORS[@]}"; do
    echo "$key: ${COLORS[$key]}"
done

String Manipulation

๐Ÿ”น String Operations

STRING="Hello World"

# Length
echo "${#STRING}"

# Substring
echo "${STRING:0:5}"  # Hello
echo "${STRING:6}"    # World

# Replace
echo "${STRING/World/Universe}"  # Replace first
echo "${STRING//o/0}"            # Replace all

# Uppercase/Lowercase
echo "${STRING^^}"  # HELLO WORLD
echo "${STRING,,}"  # hello world

# Remove prefix/suffix
FILE="document.txt"
echo "${FILE%.txt}"    # document
echo "${FILE#*.}"      # txt

File Operations

๐Ÿ”น File Handling

# Read file
while IFS= read -r line; do
    echo "$line"
done < file.txt

# Write to file
echo "Hello" > file.txt   # Overwrite
echo "World" >> file.txt  # Append

# Check if file exists
if [ -f "file.txt" ]; then
    echo "File exists"
fi

# Create directory
mkdir -p /path/to/directory

# Copy files
cp source.txt destination.txt

# Move files
mv old.txt new.txt

# Delete files
rm file.txt
rm -rf directory/

Process Management

๐Ÿ”น Process Control

# Run in background
long_running_command &

# Get process ID
PID=$!

# Wait for process
wait $PID

# Kill process
kill $PID
kill -9 $PID  # Force kill

# Check if process is running
if ps -p $PID > /dev/null; then
    echo "Process is running"
fi

Error Handling

๐Ÿ”น Exit Codes and Traps

#!/bin/bash
set -e  # Exit on error
set -u  # Exit on undefined variable
set -o pipefail  # Exit on pipe failure

# Trap errors
trap 'echo "Error on line $LINENO"' ERR

# Cleanup on exit
cleanup() {
    echo "Cleaning up..."
    rm -f /tmp/tempfile
}
trap cleanup EXIT

# Check command success
if ! command -v docker &> /dev/null; then
    echo "Docker not found"
    exit 1
fi

# Custom error handling
function error_exit() {
    echo "Error: $1" >&2
    exit 1
}

[ -f "required.txt" ] || error_exit "required.txt not found"

Best Practices

โœ… Script Template

#!/bin/bash

# Script: backup.sh
# Description: Backup files to remote server
# Author: Your Name
# Date: 2024-01-01

set -euo pipefail  # Exit on error, undefined vars, pipe failures

# Constants
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly BACKUP_DIR="/backup"
readonly LOG_FILE="/var/log/backup.log"

# Functions
log() {
    echo "[$(date +'%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"
}

error() {
    log "ERROR: $*" >&2
    exit 1
}

cleanup() {
    log "Cleaning up..."
    # Cleanup code here
}

main() {
    trap cleanup EXIT
    
    log "Starting backup..."
    
    # Main logic here
    
    log "Backup completed successfully"
}

# Run main function
main "$@"

โœ… Best Practices

  1. Use shellcheck for linting
  2. Quote variables to prevent word splitting
  3. Use set -euo pipefail for safety
  4. Add error handling and logging
  5. Make scripts idempotent
  6. Use functions for organization
  7. Add usage/help messages
  8. Use meaningful variable names

๐ŸŽ“ Shell Scripting Master Class Complete