Skip to content

Instantly share code, notes, and snippets.

@meysam81
Created August 19, 2025 09:11
Show Gist options
  • Select an option

  • Save meysam81/bc464849e5d75847bd85021903f30242 to your computer and use it in GitHub Desktop.

Select an option

Save meysam81/bc464849e5d75847bd85021903f30242 to your computer and use it in GitHub Desktop.
Check for availability of a given product name and its possible TLD domains using DNS check and WHOIS API call; use at your own discretion!
#!/bin/bash
# Unified Domain Generator & Availability Checker
# Can accept either raw names to generate domains or a list of domains to check
# Usage: ./domain_tool.sh --names names.txt [options]
# ./domain_tool.sh --domains domains.txt [options]
# Color codes
RED='\033[0;31m'
GREEN='\033[0;32m'
BLUE='\033[0;34m'
YELLOW='\033[1;33m'
CYAN='\033[0;36m'
NC='\033[0m'
# Default B2B SaaS-friendly TLDs
DEFAULT_TLDS=(
"com" # Universal, most trusted
"io" # Tech startups
"app" # Applications
"so" # Trendy for SaaS
"dev" # Developer tools
"ai" # AI/ML companies
"co" # Company/startup alternative
"tech" # Technology companies
"cloud" # Cloud services
"tools" # SaaS tools
"software" # Software companies
"solutions" # B2B solutions
"platform" # Platform businesses
"systems" # Enterprise systems
"pro" # Professional services
)
# Function to display usage
show_usage() {
echo "Unified Domain Generator & Availability Checker"
echo ""
echo "Usage:"
echo " $0 --names <file> [options] # Generate domains from names, then check"
echo " $0 --domains <file> [options] # Check existing domain list"
echo ""
echo "Input Options:"
echo " --names FILE Input file with base names (one per line)"
echo " --domains FILE Input file with full domains (one per line)"
echo ""
echo "Generation Options (for --names mode):"
echo " -t, --tlds LIST Comma-separated list of TLDs (overrides defaults)"
echo " -a, --add-tlds LIST Add TLDs to default list"
echo " -m, --minimal Use minimal TLD set (com,io,app,so,dev,ai)"
echo " -p, --prefixes LIST Add prefixes to names (e.g., 'get,try,use')"
echo " -s, --suffixes LIST Add suffixes to names (e.g., 'app,hub,hq')"
echo ""
echo "Checking Options:"
echo " --skip-dns Skip DNS checks (faster but less accurate)"
echo " --skip-whois Skip WHOIS checks (avoids rate limiting)"
echo " --delay SECONDS Delay between checks (default: 0.5)"
echo " --available-only Only show available domains in output"
echo ""
echo "Output Options:"
echo " -o, --output FILE Base name for output files (default: domain_results)"
echo " --keep-temp Keep temporary generated domains file"
echo ""
echo "General Options:"
echo " -h, --help Show this help message"
echo ""
echo "Examples:"
echo " # Generate and check domains from names"
echo " $0 --names startup_names.txt -m --available-only"
echo ""
echo " # Check existing domain list"
echo " $0 --domains my_domains.txt --skip-whois"
echo ""
echo " # Generate with prefixes/suffixes and check"
echo " $0 --names names.txt -p 'get,try' -s 'app,hub' -t 'com,io'"
}
# Initialize variables
INPUT_MODE=""
INPUT_FILE=""
OUTPUT_BASE="domain_results"
CUSTOM_TLDS=""
ADD_TLDS=""
USE_MINIMAL=false
PREFIXES=""
SUFFIXES=""
SKIP_DNS=false
SKIP_WHOIS=false
CHECK_DELAY=0.5
AVAILABLE_ONLY=false
KEEP_TEMP=false
TEMP_DOMAINS_FILE=""
# Parse command line arguments
while [[ $# -gt 0 ]]; do
case $1 in
--names)
INPUT_MODE="names"
INPUT_FILE="$2"
shift 2
;;
--domains)
INPUT_MODE="domains"
INPUT_FILE="$2"
shift 2
;;
-t|--tlds)
CUSTOM_TLDS="$2"
shift 2
;;
-a|--add-tlds)
ADD_TLDS="$2"
shift 2
;;
-m|--minimal)
USE_MINIMAL=true
shift
;;
-p|--prefixes)
PREFIXES="$2"
shift 2
;;
-s|--suffixes)
SUFFIXES="$2"
shift 2
;;
--skip-dns)
SKIP_DNS=true
shift
;;
--skip-whois)
SKIP_WHOIS=true
shift
;;
--delay)
CHECK_DELAY="$2"
shift 2
;;
--available-only)
AVAILABLE_ONLY=true
shift
;;
-o|--output)
OUTPUT_BASE="$2"
shift 2
;;
--keep-temp)
KEEP_TEMP=true
shift
;;
-h|--help)
show_usage
exit 0
;;
*)
echo "Unknown option: $1"
show_usage
exit 1
;;
esac
done
# Validate input
if [ -z "$INPUT_MODE" ] || [ -z "$INPUT_FILE" ]; then
echo -e "${RED}Error: You must specify either --names or --domains with a file${NC}"
echo ""
show_usage
exit 1
fi
if [ ! -f "$INPUT_FILE" ]; then
echo -e "${RED}Error: File $INPUT_FILE not found${NC}"
exit 1
fi
# Function to generate domains from names
generate_domains() {
local names_file="$1"
local output_file="$2"
# Determine which TLDs to use
local tlds=()
if [ "$USE_MINIMAL" = true ]; then
tlds=("com" "io" "app" "so" "dev" "ai")
elif [ -n "$CUSTOM_TLDS" ]; then
IFS=',' read -ra tlds <<< "$CUSTOM_TLDS"
else
tlds=("${DEFAULT_TLDS[@]}")
fi
# Add additional TLDs if specified
if [ -n "$ADD_TLDS" ]; then
IFS=',' read -ra ADDITIONAL <<< "$ADD_TLDS"
tlds+=("${ADDITIONAL[@]}")
fi
# Parse prefixes and suffixes
IFS=',' read -ra PREFIX_ARRAY <<< "$PREFIXES"
IFS=',' read -ra SUFFIX_ARRAY <<< "$SUFFIXES"
# Clear output file
> "$output_file"
echo -e "${BLUE}Generating domains...${NC}"
echo -n "TLDs: "
echo "${tlds[@]}" | tr ' ' ','
[ -n "$PREFIXES" ] && echo "Prefixes: $PREFIXES"
[ -n "$SUFFIXES" ] && echo "Suffixes: $SUFFIXES"
local total_names=0
local total_domains=0
# Process each name
while IFS= read -r name || [ -n "$name" ]; do
# Clean the name
name=$(echo "$name" | tr -d '[:space:]' | tr '[:upper:]' '[:lower:]')
[ -z "$name" ] && continue
((total_names++))
# Generate variations
local variations=()
variations+=("$name")
for prefix in "${PREFIX_ARRAY[@]}"; do
[ -n "$prefix" ] && variations+=("${prefix}${name}")
done
for suffix in "${SUFFIX_ARRAY[@]}"; do
[ -n "$suffix" ] && variations+=("${name}${suffix}")
done
for prefix in "${PREFIX_ARRAY[@]}"; do
for suffix in "${SUFFIX_ARRAY[@]}"; do
[ -n "$prefix" ] && [ -n "$suffix" ] && variations+=("${prefix}${name}${suffix}")
done
done
# Generate domains with all TLDs
for variant in "${variations[@]}"; do
for tld in "${tlds[@]}"; do
echo "${variant}.${tld}" >> "$output_file"
((total_domains++))
done
done
done < "$names_file"
# Sort and remove duplicates
sort -u "$output_file" -o "$output_file"
local unique_domains=$(wc -l < "$output_file")
echo -e "${GREEN}Generated $unique_domains unique domains from $total_names names${NC}"
}
# Function to check domain using DNS
check_dns() {
local domain=$1
if [ "$SKIP_DNS" = true ]; then
echo "Skipped"
return 2
fi
if dig +short NS "$domain" 2>/dev/null | grep -q .; then
echo "Has_DNS"
return 1 # Domain has NS records (likely taken)
else
echo "No_DNS"
return 0 # No NS records (possibly available)
fi
}
# Function to check domain using WHOIS
check_whois() {
local domain=$1
if [ "$SKIP_WHOIS" = true ]; then
echo "Skipped"
return 2
fi
local whois_output
whois_output=$(timeout 5 whois "$domain" 2>/dev/null)
if echo "$whois_output" | grep -qiE "No match|Not found|No Data Found|No entries found|Status: free|available"; then
echo "Not_Found"
return 0 # Likely available
elif echo "$whois_output" | grep -qiE "Domain Name:|Registrar:|Creation Date:|Status: ACTIVE|Status: ok"; then
echo "Registered"
return 1 # Definitely taken
else
echo "Uncertain"
return 2 # Uncertain
fi
}
# Function to check domains
check_domains() {
local domains_file="$1"
local results_file="${OUTPUT_BASE}_$(date +%Y%m%d_%H%M%S).csv"
echo -e "${BLUE}Starting domain availability check...${NC}"
echo "Results will be saved to: $results_file"
echo ""
# Initialize results file
echo "Domain,DNS_Status,WHOIS_Status,Likely_Available" > "$results_file"
local total_domains=$(wc -l < "$domains_file")
local current=0
local available_domains=()
while IFS= read -r domain || [ -n "$domain" ]; do
domain=$(echo "$domain" | tr -d '[:space:]')
[ -z "$domain" ] && continue
((current++))
echo -n "[$current/$total_domains] Checking $domain... "
# Check DNS
dns_status=$(check_dns "$domain")
dns_result=$?
# Add delay before WHOIS check
sleep "$CHECK_DELAY"
# Check WHOIS
whois_status=$(check_whois "$domain")
whois_result=$?
# Determine likely availability
if { [ $dns_result -eq 0 ] || [ $dns_result -eq 2 ]; } &&
{ [ $whois_result -eq 0 ] || [ $whois_result -eq 2 ]; } &&
{ [ $dns_result -eq 0 ] || [ $whois_result -eq 0 ]; }; then
likely_available="YES"
available_domains+=("$domain")
echo -e "${GREEN}LIKELY AVAILABLE${NC}"
elif [ $dns_result -eq 1 ] || [ $whois_result -eq 1 ]; then
likely_available="NO"
echo -e "${RED}TAKEN${NC}"
else
likely_available="UNCERTAIN"
echo -e "${YELLOW}UNCERTAIN${NC}"
fi
# Save to CSV (unless available-only mode and domain is not available)
if [ "$AVAILABLE_ONLY" = false ] || [ "$likely_available" = "YES" ]; then
echo "$domain,$dns_status,$whois_status,$likely_available" >> "$results_file"
fi
done < "$domains_file"
# Summary
echo ""
echo -e "${CYAN}═══════════════════════════════════${NC}"
echo -e "${CYAN} CHECKING COMPLETE${NC}"
echo -e "${CYAN}═══════════════════════════════════${NC}"
local available_count=${#available_domains[@]}
local taken_count=$(grep -c ",NO$" "$results_file" 2>/dev/null || echo 0)
local uncertain_count=$(grep -c ",UNCERTAIN$" "$results_file" 2>/dev/null || echo 0)
echo "Summary:"
echo " Total checked: $current"
echo -e " ${GREEN}Likely available: $available_count${NC}"
echo -e " ${RED}Taken: $taken_count${NC}"
echo -e " ${YELLOW}Uncertain: $uncertain_count${NC}"
# Display available domains
if [ $available_count -gt 0 ]; then
echo ""
echo -e "${GREEN}Available domains:${NC}"
for domain in "${available_domains[@]}"; do
echo " ✓ $domain"
done
# Save available domains to separate file
available_file="${OUTPUT_BASE}_available.txt"
printf "%s\n" "${available_domains[@]}" > "$available_file"
echo ""
echo -e "${GREEN}Available domains saved to: $available_file${NC}"
fi
echo ""
echo "Full results saved to: $results_file"
}
# Main execution
echo -e "${CYAN}═══════════════════════════════════════════${NC}"
echo -e "${CYAN} Domain Generator & Availability Checker${NC}"
echo -e "${CYAN}═══════════════════════════════════════════${NC}"
echo ""
# Process based on input mode
if [ "$INPUT_MODE" = "names" ]; then
# Generate domains first
TEMP_DOMAINS_FILE="${OUTPUT_BASE}_generated_$(date +%Y%m%d_%H%M%S).txt"
generate_domains "$INPUT_FILE" "$TEMP_DOMAINS_FILE"
echo ""
# Show sample of generated domains
echo "Sample generated domains (first 5):"
head -5 "$TEMP_DOMAINS_FILE" | while read -r domain; do
echo " • $domain"
done
total_generated=$(wc -l < "$TEMP_DOMAINS_FILE")
[ $total_generated -gt 5 ] && echo " ... and $((total_generated - 5)) more"
echo ""
# Check the generated domains
check_domains "$TEMP_DOMAINS_FILE"
# Clean up temp file unless requested to keep
if [ "$KEEP_TEMP" = false ]; then
rm -f "$TEMP_DOMAINS_FILE"
else
echo "Generated domains file kept at: $TEMP_DOMAINS_FILE"
fi
else
# Direct domain checking
check_domains "$INPUT_FILE"
fi
echo ""
echo -e "${CYAN}All operations complete!${NC}"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment