Skip to content

Instantly share code, notes, and snippets.

@jackbdu
Last active March 18, 2024 23:35
Show Gist options
  • Select an option

  • Save jackbdu/1e664c154f934c5d6f6f7ec51e5df037 to your computer and use it in GitHub Desktop.

Select an option

Save jackbdu/1e664c154f934c5d6f6f7ec51e5df037 to your computer and use it in GitHub Desktop.
Generating simple redirect index.html in docs/subfolder in GitHub repo
#!/bin/bash
#
# Redirect Generator
#
# Author: Jack B. Du ([email protected])
#
# Usage:
# ./redirect-generator.sh # Interactive mode: prompts for folder name and URL.
# ./redirect-generator.sh --update-from-csv # Update redirects from CSV file interactively.
# ./redirect-generator.sh --update-from-csv --confirm-all # Update redirects from CSV file without confirmation prompts.
# ./redirect-generator.sh --help # Displays usage information and exits.
#
# Flags:
# --update-from-csv: Update redirects from a CSV file, reading folder names and URLs to create or update redirects.
# --confirm-all: When updating from the CSV file, this flag skips manual confirmation prompts for each redirect.
# --help: Displays this usage information and exits.
#
# Description:
# This script generates a redirect HTML file in the specified folder, redirecting to the provided URL.
# It validates URLs, including checks for reachability and HTTP status codes, and prompts the user for
# confirmation before proceeding with potentially unreachable or problematic URLs. The script can operate
# in an interactive mode for individual redirects or batch process updates from a CSV file. It maintains
# a CSV log of successful redirects for record-keeping and future updates.
#
# Enhancements include logging of actions for audit trails, and configuration through external files for flexibility.
# The script also supports relative URLs (starting with a dot) without prepending "https://",
# accommodating a wider range of redirect targets.
#
# Credits: Created with help from ChatGPT.
# Default configurations can be overridden by a separate configuration file.
# This allows for easier customization without modifying the script itself.
CONFIG_FILE="redirect-generator.config"
if [ -f "$CONFIG_FILE" ]; then
source "$CONFIG_FILE"
fi
# Default file locations, which can be overridden by the configuration file.
CSV_FILE="${CSV_FILE:-redirects.csv}"
LOG_FILE="${LOG_FILE:-redirect-generator.log}"
# Function for logging messages with timestamps to a log file.
# This is useful for tracking the script's operations and debugging issues.
log() {
echo "[$(date +'%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE"
}
# Ensures URLs start with http://, https://, or a dot (.). If not, https:// is prepended.
# URLs starting with a dot are typically used for relative paths, so they should be left as is.
prepend_https() {
local url=$1
# Check if URL starts with http://, https://, or a dot (.)
if ! [[ $url =~ ^https?:// ]] && ! [[ $url =~ ^\. ]]; then
url="https://${url}"
fi
echo "$url"
}
# Validates the URL's reachability and HTTP status using curl.
# Provides warnings for unreachable URLs or those that return error codes.
validate_url() {
local url=$(prepend_https "$1")
if ! curl --head --silent --fail "$url" > /dev/null; then
log "Warning: The URL '$url' is not reachable or does not exist."
read -p "Warning: The URL '$url' is not reachable or does not exist. Do you still want to proceed? (y/n): " proceed_confirmation < /dev/tty
if [[ $proceed_confirmation != [yY] ]]; then
log "Aborted by user due to unreachable URL."
echo "Aborted. Exiting script."
exit 1
fi
fi
# Check if the URL returns a 2xx status code (indicating success)
if ! curl --head --silent --fail --output /dev/null --write-out "%{http_code}" "$url" | grep -qE '^2'; then
log "Warning: The URL '$url' returned a non-successful HTTP status code."
read -p "Warning: The URL '$url' returned a non-successful HTTP status code. Do you still want to proceed? (y/n): " proceed_confirmation < /dev/tty
if [[ $proceed_confirmation != [yY] ]]; then
log "Aborted by user due to a non-successful HTTP status code."
echo "Aborted. Exiting script."
exit 1
fi
fi
echo "$url"
}
# Validates the folder name against a pattern and checks for its existence.
# Prompts for confirmation before overwriting an existing folder.
validate_folder() {
local folder_name=$(echo "$1" | tr '[:upper:]' '[:lower:]')
if [[ ! "$folder_name" =~ ^[a-z0-9_\-~.]+$ ]]; then
log "Error: Invalid folder name '$folder_name'."
echo "Error: Invalid folder name. Please use only lowercase letters, numbers, hyphens, underscores, periods, and tildes."
exit 1
fi
if [ -d "docs/${folder_name}" ]; then
read -p "The folder 'docs/${folder_name}' already exists. Do you want to overwrite it? (y/n): " overwrite_confirmation < /dev/tty
if [[ $overwrite_confirmation != [yY] ]]; then
log "Aborted by user due to existing folder 'docs/${folder_name}."
echo "Aborted. Exiting script."
exit 1
fi
fi
echo "$folder_name"
}
# Shows help information with usage instructions and options description.
# This function improves the script's usability by guiding the user.
show_help() {
echo "Usage: $0 [OPTIONS]"
echo "Options:"
echo " --update-from-csv Update redirects from a CSV file."
echo " --confirm-all Automatically confirm all updates when updating from CSV file."
echo " --help Show this help message."
echo ""
echo "Description:"
echo " This script generates a redirect HTML file in the specified folder, redirecting to the provided URL."
}
# Function to create or update the redirect HTML file
# This function also logs the creation or update action.
create_redirect_html() {
local folder_name=$1
local redirect_url=$2
# Ensure the target directory exists
mkdir -p "docs/${folder_name}" || { echo "Error: Failed to create folder 'docs/${folder_name}'."; log "Error: Failed to create folder 'docs/${folder_name}'."; exit 1; }
# Define the HTML content for the redirect
local html_content=$(cat <<EOF
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="refresh" content="0; URL='${redirect_url}'">
<style>
@keyframes fadeIn {
from { opacity: 0; }
to { opacity: 1; }
}
body {
opacity: 0; /* Initially hide the h1 */
animation: fadeIn 1s ease-out 2s forwards; /* Animation delayed by 2 second */
font-family: Ubuntu, Arial, sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
text-align: center;
}
</style>
</head>
<body>
<div>
<h1>Redirecting...</h1>
<p>If you are not redirected automatically, <a href="${redirect_url}">click here</a>.</p>
</div>
</body>
</html>
EOF
)
# Write the HTML content to the index.html file within the specified folder
local file_path="docs/${folder_name}/index.html"
echo "${html_content}" > "${file_path}"
echo "index.html file created in 'docs/${folder_name}' folder, redirecting to '${redirect_url}'."
log "Redirect for '${folder_name}' created or updated, pointing to '${redirect_url}'."
# Update or create an entry in the CSV file for the redirect
# This part keeps track of all redirects for future reference or updates
if [ -f "$CSV_FILE" ]; then
local temp_file=$(mktemp)
awk -v folder_name="$folder_name" -v redirect_url="$redirect_url" -F',' 'BEGIN {OFS=","} {if ($1 == folder_name) {$2=redirect_url; print $0; found=1} else {print $0}} END {if (!found) {print folder_name, redirect_url}}' "$CSV_FILE" > "$temp_file"
mv "$temp_file" "$CSV_FILE"
else
echo "${folder_name},${redirect_url}" > "$CSV_FILE"
fi
}
# Function to handle updates from a CSV file
# This processes each line of the CSV to update or create redirects
update_from_csv() {
local confirm_all=$1
# Check for the presence of the CSV file
if [ ! -f "$CSV_FILE" ]; then
log "Error: CSV file '$CSV_FILE' not found."
echo "Error: CSV file '$CSV_FILE' not found."
exit 1
fi
# Read each line from the CSV file and process it
while IFS=',' read -r folder_name redirect_url || [ -n "$folder_name" ]; do
# Skip header line if present
if [[ "$folder_name" == "Folder Name" ]]; then
continue
fi
# For the --confirm-all flag, bypass user confirmation
if [[ $confirm_all != "true" ]]; then
read -p "Update redirect for folder '${folder_name}' to '${redirect_url}'? (y/n): " user_confirmation < /dev/tty
if [[ $user_confirmation != [yY] ]]; then
echo "Skipping folder '${folder_name}'."
log "Update for '${folder_name}' skipped by user."
continue
fi
# Validate folder name and confirm if it already exists
folder_name=$(validate_folder "$folder_name")
if [ $? -ne 0 ]; then
# Error occurred, continue to next entry
echo "$folder_name"
continue
fi
# Validate the URL
redirect_url=$(validate_url "$redirect_url")
if [ $? -ne 0 ]; then
# Error occurred, continue to next entry
echo "$redirect_url"
continue
fi
fi
# Create or update the redirect
create_redirect_html "$folder_name" "$redirect_url"
done < "$CSV_FILE"
}
# Main execution logic
main() {
# Parsing command-line options to set script behavior.
# Supports updating from a CSV file, automatic confirmation, and showing help.
while [[ "$#" -gt 0 ]]; do
case $1 in
--update-from-csv) update_from_csv="true"; shift ;;
--confirm-all) confirm_all="true"; shift ;;
--help) show_help; exit 0 ;;
*) echo "Unknown option: $1"; show_help; exit 1 ;;
esac
done
if [[ $update_from_csv == "true" ]]; then
update_from_csv "$confirm_all"
else
# Prompt user to enter the folder name where they want to create the index.html file
read -p "Enter the folder name where you want to create the index.html file: " folder_name
# Validate folder name and confirm if it already exists
folder_name=$(validate_folder "$folder_name")
if [ $? -ne 0 ]; then
echo "$folder_name"
# Error occurred, exit script
exit 1
fi
# Prompt user to enter the URL they want to redirect to
read -p "Enter the URL you want to redirect to: " redirect_url
# Validate the URL
redirect_url=$(validate_url "$redirect_url")
if [ $? -ne 0 ]; then
echo "$redirect_url"
# Error occurred, exit script
exit 1
fi
# Create the redirect HTML file
create_redirect_html "$folder_name" "$redirect_url"
fi
}
# Execute the main function with all provided arguments
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment