BASH
SCRIPTING

// Automate everything. Own your shell.

THE SHELL IS YOUR POWERHOUSE.

While others click around their GUIs, you'll be orchestrating your entire system with a few keystrokes. Bash scripts turn repetitive tasks into single commands. Your time is too valuable to waste on manual work.

AUTOMATION IS FREEDOM.

Write a script once, run it forever. Schedule backups, monitor systems, process files, deploy applicationsβ€”all automatically. When your computer works for you, you're finally in control.

THE UNIX PHILOSOPHY LIVES IN BASH.

Small tools, combined beautifully. Pipes that transform data like magic. This is how the original hackers built the internetβ€”and how you can too.

START SCRIPTING

// Your Training Path

Click a lesson to begin

LESSON 01

Your First Script

Create and execute your first bash script. Learn the shebang and basic script structure.

Beginner
LESSON 02

Variables and Parameters

Store data in variables, work with command-line arguments, and understand environment variables.

Beginner
LESSON 03

Conditionals

Make decisions with if/else statements, test conditions, and boolean logic.

Beginner
LESSON 04

Loops

Iterate with for and while loops. Process multiple files and automate repetitive tasks.

Beginner
LESSON 05

Functions

Organize code with functions, pass parameters, and return values.

Beginner
LESSON 06

Arrays and Strings

Work with arrays, manipulate strings, and use advanced text processing.

Intermediate
LESSON 07

Exit Codes and Error Handling

Check command success, handle errors gracefully, and debug your scripts.

Intermediate
LESSON 08

Real-World Automation

Build practical scripts for backups, monitoring, and system administration.

Intermediate
LESSON 09

Input/Output Redirection

Master stdin, stdout, stderr, pipes, and here documents.

Intermediate
LESSON 10

Text Processing Tools

Use sed, awk, and grep for powerful text manipulation.

Intermediate
LESSON 11

Advanced Arguments

Parse command-line options with getopts and manage arguments.

Intermediate
LESSON 12

Debugging & Best Practices

Debug scripts, optimize performance, and write production-ready code.

Advanced

// Tools & References

GNU Bash Reference

Official Bash Documentation

bash manual

ShellCheck

Static Analysis Tool

shellcheck.net

Advanced Bash Scripting

Free Online Book

ABS Guide

Bash Hackers Wiki

Human-readable Bash Docs

bash-hackers.org

explainshell

Parse Shell Commands

explainshell.com

TLDP Bash Guide

Beginner to Advanced

Bash Beginners

// Lesson 01: Your First Script

Γ—

The Shebang

Every bash script starts with a shebangβ€”the magic line that tells the system which interpreter to use:

# This tells Linux to use bash to run this script #!/bin/bash

Creating Your First Script

Let's create a simple script that greets you:

$ cat > hello.sh << 'EOF' #!/bin/bash # My first bash script echo "Hello, rebel! Welcome to bash scripting." echo "Today is $(date)" EOF

Now make it executable and run it:

$ chmod +x hello.sh $ ./hello.sh Hello, rebel! Welcome to bash scripting. Today is Tue Feb 24 12:00:00 EST 2026

Comments

Lines starting with # are comments. Use them liberallyβ€”your future self will thank you:

# This script backs up my documents folder # It creates a timestamped archive # Usage: ./backup.sh
Pro Tip: The shebang line #!/bin/bash must be the very first line of your script. No blank lines before it!

Quiz

1. What does the shebang line do?

Hint: It tells Linux how to run the script.

2. What command makes a script executable?

Hint: change mode + execute

Show Answers

Answers

  1. tells the system which interpreter to use
  2. chmod +x

// Lesson 02: Variables and Parameters

Γ—

Creating Variables

Variables store data for later use. No dollar sign when assigning, but use $ when reading:

# Assign a value (no $) name="Rebel" count=42 # Read the value (with $) echo $name echo $count
Critical: There must be NO spaces around the = sign. name="Rebel" works, but name = "Rebel" does not!

Command Substitution

Capture command output into variables using $(command) or backticks:

# Get current date today=$(date +%Y-%m-%d) echo $today # Count files in current directory file_count=$(ls -1 | wc -l) echo $file_count files found

Command-Line Arguments

Scripts can accept arguments passed from the command line:

# script.sh arg1 arg2 arg3 $0 # script.sh (the script name) $1 # arg1 (first argument) $2 # arg2 (second argument) $@ # all arguments as a list $# # number of arguments

Example script:

#!/bin/bash echo "Script: $0" echo "First arg: $1" echo "Second arg: $2" echo "Total args: $#"

Environment Variables

Access system information through environment variables:

echo $HOME # Your home directory echo $USER # Your username echo $PATH # Executable search path echo $PWD # Current directory echo $HOSTNAME # Computer name

Quiz

1. How do you read a variable value in bash?

Hint: It starts with a dollar sign.

2. What variable holds all command-line arguments?

Show Answers

Answers

  1. $
  2. $@

// Lesson 03: Conditionals

Γ—

The if Statement

Make decisions based on conditions:

if [ $age -ge 18 ]; then echo "You are an adult" fi

Comparison Operators

Numbers use these operators:

-eq # equal -ne # not equal -lt # less than -le # less than or equal -gt # greater than -ge # greater than or equal

Strings use these operators:

= # equal (single =) != # not equal -z # is empty -n # is not empty

if/else

if [ $1 = "admin" ]; then echo "Welcome, Administrator" else echo "Welcome, $1" fi

elif (Else If)

if [ $score -ge 90 ]; then echo "Grade: A" elif [ $score -ge 80 ]; then echo "Grade: B" elif [ $score -ge 70 ]; then echo "Grade: C" else echo "Grade: F" fi

File Tests

Check file properties:

-e # file exists -f # regular file exists -d # directory exists -r # file is readable -w # file is writable -x # file is executable
Example: Check if a file exists before deleting:
if [ -f "$filename" ]; then
    rm "$filename"
    echo "Deleted $filename"
else
    echo "File not found"
fi
                    

Quiz

1. What operator checks if two strings are equal?

2. What flag checks if a file is a directory?

Show Answers

Answers

  1. =
  2. -d

// Lesson 04: Loops

Γ—

For Loops

Iterate over a list of items:

for color in red green blue; do echo "Color: $color" done

Output:

Color: red Color: green Color: blue

Loop Over Files

Process all files in a directory:

for file in *.txt; do echo "Processing: $file" done

For Loop with Sequence

Use brace expansion for number ranges:

# Count from 1 to 5 for i in {1..5}; do echo "Number: $i" done

While Loops

Loop while a condition is true:

count=1 while [ $count -le 5 ]; do echo "Count: $count" count=$((count + 1)) done

Reading Input

Read file line by line:

while read line; do echo "Line: $line" done < file.txt

Loop Control

break # exit the loop entirely continue # skip to next iteration
Example: Find first file containing "error":
for file in *.log; do
    if grep -q "error" "$file"; then
        echo "Found error in: $file"
        break
    fi
done
                    

Quiz

1. What command skips to the next iteration of a loop?

2. What syntax loops from 1 to 10?

Show Answers

Answers

  1. continue
  2. {1..10}

// Lesson 05: Functions

Γ—

Defining Functions

Two ways to define functions in bash:

# Method 1: name() syntax greet() { echo "Hello!" } # Method 2: function keyword function farewell { echo "Goodbye!" }

Calling Functions

greet # calls the greet function farewell # calls the farewell function

Function Parameters

Functions use $1, $2, etc. just like scripts:

greet_user() { echo "Hello, $1!" } greet_user Alice # Output: Hello, Alice! greet_user Bob # Output: Hello, Bob!

Return Values

Bash functions return exit codes (0 = success, non-zero = error):

is_admin() { if [ $1 = "admin" ]; then return 0 # success else return 1 # failure fi } is_admin $user if [ $? -eq 0 ]; then echo "User is admin" fi

Scope: Local Variables

Use local to keep variables from leaking:

calculate() { local result=$(( $1 * $2 )) echo $result } result=100 # global variable calculate 5 10 # echoes 50, doesn't change global echo $result # still 100
Best Practice: Always use local for variables inside functions unless you intentionally want them to be global.

Quiz

1. How do you keep a variable local inside a function?

2. What does $? contain after a function returns?

Show Answers

Answers

  1. local
  2. exit code

// Lesson 06: Arrays and Strings

Γ—

Arrays

Store multiple values in a single variable:

# Create an array fruits=("apple" "banana" "cherry" "date") # Access elements (0-indexed) echo ${fruits[0]} # apple echo ${fruits[2]} # cherry # Get all elements echo ${fruits[@]} # all fruits # Get array length echo ${#fruits[@]} # 4

Array Operations

# Add element fruits+=("elderberry") # Remove element (by index) unset fruits[1] # Slice (elements 1-3) echo ${fruits[@]:1:3}

String Operations

str="Hello, Rebel!" # String length echo ${#str} # 13 # Substring echo ${str:0:5} # Hello # Replace echo ${str/Rebel/World} # Hello, World!

Pattern Matching

file="document.pdf" # Remove shortest match from beginning echo ${file#*.} # pdf # Remove longest match from beginning echo ${file##*.} # pdf # Remove shortest match from end echo ${file%.*} # document # Remove longest match from end echo ${file%%.*} # document
Practical use: Get file extensions and names:
filename="report.2024.pdf"
ext="${filename##*.}"     # pdf
base="${filename%.*}"     # report.2024
                    

Quiz

1. How do you get the length of an array?

2. What removes the shortest match from the end of a string?

Show Answers

Answers

  1. ${#array[@]}
  2. %

// Lesson 07: Exit Codes and Error Handling

Γ—

Exit Codes

Every command returns an exit code: 0 = success, non-zero = failure:

$ ls /valid/path $ echo $? 0 $ ls /invalid/path $ echo $? 2

Checking Exit Codes

if $command; then echo "Command succeeded" else echo "Command failed with code $?" fi

set Options

Automatically handle errors in scripts:

set -e # Exit on any error set -u # Exit on undefined variable set -o pipefail # Catch errors in pipelines

Add at the top of your script:

#!/bin/bash set -euo pipefail

Custom Exit Codes

Return specific codes for different errors:

#!/bin/bash if [ $# -lt 1 ]; then echo "Usage: $0 " >&2 exit 1 # Usage error fi if [ ! -f $1 ]; then echo "Error: File not found" >&2 exit 2 # File not found fi exit 0 # Success

Trap Errors

Execute cleanup code when script exits:

cleanup() { echo "Cleaning up..." rm -f /tmp/tempfile } trap cleanup EXIT
Standard Exit Codes:
0 = success
1 = general error
2 = misuse of command
126 = command not executable
127 = command not found

Quiz

1. What exit code means success?

2. What option makes the script exit on any command failure?

Show Answers

Answers

  1. 0
  2. set -e

// Lesson 08: Real-World Automation

Γ—

Automated Backup Script

#!/bin/bash set -euo pipefail SOURCE="/home/user/documents" BACKUP_DIR="/backup" DATE=$(date +%Y-%m-%d) mkdir -p $BACKUP_DIR echo "Starting backup of $SOURCE..." if tar -czf $BACKUP_DIR/backup-$DATE.tar.gz $SOURCE; then echo "Backup completed successfully" exit 0 else echo "Backup failed!" >&2 exit 1 fi

System Monitor Script

#!/bin/bash set -euo pipefail CPU=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1) MEM=$(free | grep Mem | awk '{printf "%.1f", $3/$2 * 100}') DISK=$(df -h / | tail -1 | awk '{print $5}' | cut -d'%' -f1) echo "=== System Status ===" echo "CPU: $CPU%" echo "Memory: $MEM%" echo "Disk: $DISK%" # Alert if usage is high if [ $CPU -gt 90 ] || [ $MEM -gt 90 ]; then echo "WARNING: High resource usage!" >&2 fi

Batch File Processor

#!/bin/bash set -euo pipefail PROCESSED=0 for file in *.csv; do echo "Processing $file..." # Skip if not a file [ -f $file ] || continue # Process the file tail -n +2 $file | sort > processed/$file PROCESSED=$((PROCESSED + 1)) done echo "Processed $PROCESSED files"

Scheduling with Cron

Make scripts run automatically:

# Edit crontab $ crontab -e # Add lines like: # Run backup every day at 2am 0 2 * * * /home/user/scripts/backup.sh # Run every hour 0 * * * * /home/user/scripts/monitor.sh # Run every Monday at 9am 0 9 * * 1 /home/user/scripts/weekly-report.sh
Crontab Format:
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ minute (0-59)
β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€ hour (0-23)
β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€ day of month (1-31)
β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€β”€β”€ month (1-12)
β”‚ β”‚ β”‚ β”‚ β”Œβ”€β”€β”€β”€β”€ day of week (0-6, Sunday=0)
β”‚ β”‚ β”‚ β”‚ β”‚
* * * * * command

Quiz

1. What does "0 2 * * *" mean in crontab?

Hint: minute hour day month weekday

2. What does set -euo pipefail do?

Hint: It makes the script stop on errors and undefined variables.

Show Answers

Answers

  1. 2am
  2. exit on error

// Lesson 09: Input/Output Redirection

Γ—

Standard Streams

Every process has three standard streams:

stdin (0) # Standard input - keyboard stdout (1) # Standard output - screen stderr (2) # Standard error - screen

Output Redirection

# Redirect stdout to file (overwrite) echo "hello" > output.txt # Redirect stdout to file (append) echo "world" >> output.txt # Redirect stderr to file ls /invalid 2> errors.txt # Redirect both stdout and stderr command > all.txt 2>&1

Input Redirection

# Read from file instead of keyboard while read line; do echo "Line: $line" done < input.txt # Here document (inline input) cat << 'EOF' This is line 1 This is line 2 This is line 3 EOF

Pipes

Connect commands together - output of one becomes input of another:

# Chain commands ls -la | grep ".txt" | wc -l # Count lines in file cat file.txt | wc -l # Sort unique count cat data.txt | sort | uniq -c

Process Substitution

# Compare two file listings diff <(ls dir1) <(ls dir2) # Read from multiple sources cat <(echo "header") file.txt <(echo "footer")

Quiz

1. What file descriptor is stderr?

2. What operator appends output to a file?

Show Answers

Answers

  1. 2
  2. >>

// Lesson 10: Text Processing Tools

Γ—

grep - Pattern Matching

Search for patterns in text:

# Basic search grep "error" logfile.txt # Case-insensitive grep -i "error" logfile.txt # Show line numbers grep -n "error" logfile.txt # Invert match (lines WITHOUT error) grep -v "error" logfile.txt # Recursive search grep -r "function" src/

sed - Stream Editor

Find and replace text:

# Replace first occurrence per line sed 's/old/new/' file.txt # Replace all occurrences sed 's/old/new/g' file.txt # Replace on specific line number sed '5s/old/new/' file.txt # Delete lines matching pattern sed '/^$/d' file.txt # Edit file in place sed -i 's/old/new/g' file.txt

awk - Text Processing

Powerful column-based processing:

# Print first column awk '{print $1}' data.txt # Print specific columns awk -F: '{print $1, $3}' /etc/passwd # Print lines longer than 80 chars awk 'length > 80' file.txt # Sum column awk '{sum+=$1} END {print sum}' numbers.txt # Conditional printing awk '$3 > 50 {print $1, $3}' data.txt

Combining Tools

# Real-world: Find errors, show context grep -n "ERROR" app.log | awk -F: '{print "Line " $1 ": " $2}' # Process CSV data awk -F, '$3 > 1000 {print $1 " owes $" $3}' customers.csv
Pro Tip: These tools are designed to work together. Pipe them to build powerful data processing pipelines.

Quiz

1. Which flag makes grep case-insensitive?

2. What sed command replaces all occurrences?

Show Answers

Answers

  1. -i
  2. s/old/new/g

// Lesson 11: Advanced Arguments

Γ—

The shift Command

Process arguments one by one:

#!/bin/bash while [ $# -gt 0 ]; do echo "Processing: $1" shift done

getopts - Option Parsing

Handle command-line flags properly:

#!/bin/bash while getopts ":vhf:o:" opt; do case $opt in v) VERBOSE=1 ;; f) FILE=$OPTARG ;; o) OUTPUT=$OPTARG ;; \?) echo "Invalid option: -$OPTARG" >&2 ;; :) echo "Option -$OPTARG requires an argument." >&2 ;; esac done echo "File: $FILE, Output: $OUTPUT, Verbose: $VERBOSE"

Usage:

./script.sh -f input.txt -o result.txt -v # -f requires argument, -v is a flag

Argument Validation

if [ $# -lt 2 ]; then echo "Usage: $0 " >&2 exit 1 fi if [ ! -f $1 ]; then echo "Error: Input file '$1' not found" >&2 exit 2 fi

Default Values

OUTPUT=${OUTPUT:-"output.txt"} # Uses "output.txt" if OUTPUT is empty MAX=${MAX:-100} # Uses 100 if MAX is empty

Quiz

1. What command moves to the next argument?

2. In getopts, what stores the option letter?

Show Answers

Answers

  1. shift
  2. opt

// Lesson 12: Debugging & Best Practices

Γ—

Debug Mode

Use -x to trace execution:

# Run script in debug mode bash -x script.sh # Add to script for debugging section set -x # your code here set +x

Debug Options

set -x # Print commands before execution set -v # Print input lines as read set -e # Exit on error set -u # Exit on undefined variable set -o pipefail # Exit if any command in pipe fails set -n # Syntax check only (no execution)

Common Pitfalls

# WRONG: Spaces around = name = "value" # RIGHT: No spaces name="value" # WRONG: Glob expands ls *.txt # Fails if no txt files # RIGHT: Quote variables ls "*.txt" ls "$file"

Best Practices

# Always use these at the top #!/bin/bash set -euo pipefail IFS=$'\n\t' # Always quote variables echo "$var" # Safe echo $var # Dangerous # Use descriptive names BACKUP_SOURCE="/home/data" # Clear bs="/home/data" # Unclear # Use functions for organization main() { parse_args $@ validate run_backup }

Testing Scripts

# Syntax check bash -n script.sh # Dry run (echo commands) bash -n script.sh && echo "OK" # Check for unset variables bash -u script.sh
Production Script Template:
#!/bin/bash
set -euo pipefail
IFS=$'\n\t'

log() { echo "[$(date)] $*"; }
error() { echo "[ERROR] $*" >&2; exit 1; }

main() {
    log "Starting"
    # your code here
    log "Done"
}

main "$@"
                    

Quiz

1. What flag enables command tracing?

2. Why quote variables?

Show Answers

Answers

  1. -x
  2. prevent word splitting