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:
- Bash Guide: https://mywiki.wooledge.org/BashGuide
- Advanced Bash Scripting: https://tldp.org/LDP/abs/html/
- ShellCheck: https://www.shellcheck.net/ (validate scripts)
Next Steps
- Write scripts daily - automate everything!
- Use ShellCheck to validate your scripts
- Study real scripts in /usr/bin, /usr/local/bin
- Build your toolbox of reusable functions
- 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."