By Davy Rogers. Use these techniques only in environments you own or have explicit permission to test.

Bash: Scripting Basics

Bash scripting transforms individual commands into powerful automation tools. Whether you're automating reconnaissance, processing scan results, or building custom tools, scripting is essential for every penetration tester. This lesson covers the fundamentals to get you writing practical scripts.

What You'll Learn

  • Creating and running bash scripts
  • Variables and user input
  • Conditional statements (if/else)
  • Loops (for, while, until)
  • Functions
  • Command-line arguments
  • Exit codes and error handling
  • Practical pentesting scripts

Your First Script

Creating a Script

1. Create file with .sh extension:

nano first_script.sh

2. Add shebang and commands:

#!/bin/bash
# This is a comment

echo "Hello, World!"
echo "This is my first script"

3. Make executable:

chmod +x first_script.sh

4. Run script:

./first_script.sh

The Shebang (#!)

#!/bin/bash          # Use bash interpreter
#!/usr/bin/env bash  # Find bash in PATH (more portable)
#!/bin/sh            # Use sh (minimal shell)
#!/usr/bin/python3   # Python script

Why it matters: Tells system which interpreter to use.


Variables

Declaring Variables

#!/bin/bash

# Variable assignment (no spaces around =!)
name="Alice"
age=25
target="192.168.1.1"

# Using variables
echo "Name: $name"
echo "Age: $age"
echo "Target: $target"

Variable Rules

✓ name="value"       # Correct
✗ name = "value"     # Wrong! (spaces)
✓ my_var="test"      # Underscore OK
✓ myVar123="test"    # Numbers OK (not first char)
✗ 123var="test"      # Can't start with number

Reading User Input

#!/bin/bash

echo "What's your name?"
read name

echo "Hello, $name!"

With prompt:

read -p "Enter target IP: " target
echo "Scanning $target..."

Silent input (passwords):

read -sp "Enter password: " password
echo ""  # New line
echo "Password saved"

Command Substitution

Capture Command Output

# Method 1: $()
current_date=$(date)
echo "Today is: $current_date"

# Method 2: `` (backticks - older style)
current_user=`whoami`
echo "User: $current_user"

# Practical examples
target_ip=$(ping -c 1 google.com | grep "PING" | cut -d' ' -f3 | tr -d '()')
file_count=$(ls | wc -l)

Conditional Statements

if Statement

#!/bin/bash

if [ condition ]; then
    # commands
fi

Example:

#!/bin/bash

read -p "Enter a number: " num

if [ $num -gt 10 ]; then
    echo "$num is greater than 10"
fi

if-else Statement

#!/bin/bash

read -p "Enter a number: " num

if [ $num -gt 10 ]; then
    echo "$num is greater than 10"
else
    echo "$num is 10 or less"
fi

if-elif-else Statement

#!/bin/bash

read -p "Enter your age: " age

if [ $age -lt 18 ]; then
    echo "You are a minor"
elif [ $age -ge 18 ] && [ $age -lt 65 ]; then
    echo "You are an adult"
else
    echo "You are a senior"
fi

Comparison Operators

Numeric comparisons:

-eq  = Equal to
-ne  = Not equal to
-gt  = Greater than
-ge  = Greater than or equal
-lt  = Less than
-le  = Less than or equal

String comparisons:

=    = Equal
!=   = Not equal
-z   = String is empty
-n   = String is not empty

File tests:

-e file  = File exists
-f file  = Regular file exists
-d dir   = Directory exists
-r file  = File is readable
-w file  = File is writable
-x file  = File is executable

Examples:

# Numeric
if [ $num -eq 10 ]; then echo "Equal to 10"; fi

# String
if [ "$name" = "admin" ]; then echo "Admin user"; fi

# File
if [ -f "/etc/passwd" ]; then echo "File exists"; fi

Logical Operators

# AND (&&)
if [ $age -ge 18 ] && [ $age -lt 65 ]; then
    echo "Adult"
fi

# OR (||)
if [ "$user" = "root" ] || [ "$user" = "admin" ]; then
    echo "Privileged user"
fi

# NOT (!)
if [ ! -f "file.txt" ]; then
    echo "File doesn't exist"
fi

Loops

for Loop

Basic syntax:

for variable in list; do
    commands
done

Examples:

# Loop through list
for color in red green blue; do
    echo "Color: $color"
done

# Loop through numbers
for i in 1 2 3 4 5; do
    echo "Number: $i"
done

# Range with brace expansion
for i in {1..10}; do
    echo "Count: $i"
done

# C-style for loop
for ((i=1; i<=10; i++)); do
    echo "Iteration $i"
done

# Loop through files
for file in *.txt; do
    echo "Processing: $file"
done

# Loop through command output
for user in $(cat /etc/passwd | cut -d: -f1); do
    echo "User: $user"
done

while Loop

Basic syntax:

while [ condition ]; do
    commands
done

Examples:

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

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

# Infinite loop
while true; do
    echo "Running..."
    sleep 1
done

# Menu loop
while true; do
    read -p "Continue? (y/n): " answer
    if [ "$answer" = "n" ]; then
        break
    fi
done

until Loop

Runs until condition is true:

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

Functions

Defining Functions

Method 1:

function greet {
    echo "Hello, World!"
}

Method 2:

greet() {
    echo "Hello, World!"
}

Calling function:

greet  # Output: Hello, World!

Functions with Parameters

#!/bin/bash

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

# Call function
greet "Alice"   # Output: Hello, Alice!
greet "Bob"     # Output: Hello, Bob!

Multiple parameters:

#!/bin/bash

user_info() {
    echo "Name: $1"
    echo "Age: $2"
    echo "City: $3"
}

user_info "Alice" 25 "NYC"

Special variables in functions:

$1, $2, $3...  = Parameters (arguments)
$@             = All parameters
$#             = Number of parameters
$0             = Script name

Return Values

#!/bin/bash

is_root() {
    if [ $(id -u) -eq 0 ]; then
        return 0  # Success (root)
    else
        return 1  # Failure (not root)
    fi
}

# Check function return
if is_root; then
    echo "Running as root"
else
    echo "Not root"
fi

Command-Line Arguments

Accessing Arguments

#!/bin/bash

echo "Script name: $0"
echo "First argument: $1"
echo "Second argument: $2"
echo "All arguments: $@"
echo "Number of arguments: $#"

Usage:

./script.sh arg1 arg2 arg3
# Output:
# Script name: ./script.sh
# First argument: arg1
# Second argument: arg2
# All arguments: arg1 arg2 arg3
# Number of arguments: 3

Checking Arguments

#!/bin/bash

if [ $# -eq 0 ]; then
    echo "Usage: $0 <target>"
    exit 1
fi

target=$1
echo "Scanning $target..."

Exit Codes

What Are Exit Codes?

0   = Success
1-255 = Error

Check last exit code: echo $?

Examples:

#!/bin/bash

# Successful command
ls /
echo "Exit code: $?"  # 0

# Failed command
ls /nonexistent
echo "Exit code: $?"  # 2 (error)

Setting Exit Codes

#!/bin/bash

if [ ! -f "$1" ]; then
    echo "Error: File not found"
    exit 1  # Exit with error
fi

echo "Processing $1..."
exit 0  # Exit successfully

Practical Pentesting Scripts

Script 1: Port Scanner

#!/bin/bash

# Simple port scanner

if [ $# -ne 2 ]; then
    echo "Usage: $0 <target> <port-range>"
    echo "Example: $0 192.168.1.1 1-100"
    exit 1
fi

target=$1
ports=$2

echo "Scanning $target for ports $ports..."

IFS='-' read -ra RANGE <<< "$ports"
start=${RANGE[0]}
end=${RANGE[1]}

for port in $(seq $start $end); do
    timeout 1 bash -c "echo >/dev/tcp/$target/$port" 2>/dev/null && \
        echo "Port $port is OPEN"
done

Script 2: Subdomain Brute Force

#!/bin/bash

# Subdomain brute forcer

if [ $# -ne 2 ]; then
    echo "Usage: $0 <domain> <wordlist>"
    exit 1
fi

domain=$1
wordlist=$2

if [ ! -f "$wordlist" ]; then
    echo "Error: Wordlist not found"
    exit 1
fi

echo "Brute forcing subdomains for $domain..."

while read subdomain; do
    result=$(host "$subdomain.$domain" 2>/dev/null)
    if echo "$result" | grep -q "has address"; then
        echo "[+] Found: $subdomain.$domain"
        echo "$result"
    fi
done < "$wordlist"

Script 3: Log Analyzer

#!/bin/bash

# Analyze web server logs

if [ $# -ne 1 ]; then
    echo "Usage: $0 <logfile>"
    exit 1
fi

logfile=$1

if [ ! -f "$logfile" ]; then
    echo "Error: Log file not found"
    exit 1
fi

echo "=== Log Analysis for $logfile ==="
echo ""

echo "Top 10 IP addresses:"
cat "$logfile" | cut -d' ' -f1 | sort | uniq -c | sort -rn | head -10
echo ""

echo "Top 10 URLs:"
cat "$logfile" | cut -d' ' -f7 | sort | uniq -c | sort -rn | head -10
echo ""

echo "404 Errors:"
grep " 404 " "$logfile" | wc -l
echo ""

echo "500 Errors:"
grep " 500 " "$logfile" | wc -l

Script 4: Ping Sweep

#!/bin/bash

# Ping sweep script

if [ $# -ne 1 ]; then
    echo "Usage: $0 <network>"
    echo "Example: $0 192.168.1"
    exit 1
fi

network=$1

echo "Scanning $network.0/24..."

for i in {1..254}; do
    ping -c 1 -W 1 "$network.$i" &>/dev/null && \
        echo "$network.$i is UP" &
done

wait
echo "Scan complete"

Script 5: Backup Script

#!/bin/bash

# Backup important files

backup_dir="/backup/$(date +%Y%m%d)"
source_dir="/var/www/html"

echo "Creating backup directory: $backup_dir"
mkdir -p "$backup_dir"

echo "Backing up $source_dir..."
tar -czf "$backup_dir/backup.tar.gz" "$source_dir" 2>/dev/null

if [ $? -eq 0 ]; then
    echo "Backup successful!"
    echo "Size: $(du -h $backup_dir/backup.tar.gz | cut -f1)"
else
    echo "Backup failed!"
    exit 1
fi

Practical Exercises

Exercise 1: Hello Script

#!/bin/bash

# Create your first script
read -p "What's your name? " name
echo "Hello, $name! Welcome to bash scripting!"

Exercise 2: Calculator

#!/bin/bash

read -p "Enter first number: " num1
read -p "Enter second number: " num2

echo "Sum: $((num1 + num2))"
echo "Difference: $((num1 - num2))"
echo "Product: $((num1 * num2))"
echo "Quotient: $((num1 / num2))"

Exercise 3: File Checker

#!/bin/bash

read -p "Enter filename: " filename

if [ -e "$filename" ]; then
    echo "File exists!"
    
    if [ -f "$filename" ]; then
        echo "It's a regular file"
    elif [ -d "$filename" ]; then
        echo "It's a directory"
    fi
    
    if [ -r "$filename" ]; then
        echo "You can read it"
    fi
else
    echo "File doesn't exist"
fi

Quick Reference

Shebang:
#!/bin/bash

Variables:
name="value"         # Assign
echo "$name"         # Use
read var             # User input
var=$(command)       # Command substitution

Conditionals:
if [ condition ]; then
    commands
elif [ condition ]; then
    commands
else
    commands
fi

Comparisons:
-eq -ne -gt -ge -lt -le    # Numeric
= !=                       # String
-e -f -d -r -w -x          # File tests

Loops:
for i in list; do ... done
while [ cond ]; do ... done
until [ cond ]; do ... done

Functions:
function_name() {
    echo "$1"    # First parameter
}

Arguments:
$0  = Script name
$1  = First argument
$@  = All arguments
$#  = Argument count
$?  = Last exit code

Exit:
exit 0  # Success
exit 1  # Error

Resources

Man Pages:

man bash
man test    # For [ ] conditions

Online:


Next Steps

  1. Write scripts daily - automate everything!
  2. Use ShellCheck to validate your scripts
  3. Study real scripts in /usr/bin, /usr/local/bin
  4. Build your toolbox of reusable functions
  5. Practice OverTheWire Bandit (next lesson!)

Bash scripting transforms you from command executor to automation master. Start simple, practice constantly, and soon you'll be writing powerful tools!


"Bash scripting: Because clicking is for amateurs."