Skip to content

Instantly share code, notes, and snippets.

@CastleCorp
Last active June 20, 2023 22:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CastleCorp/d90c569eef1660440558df73e10564b3 to your computer and use it in GitHub Desktop.
Save CastleCorp/d90c569eef1660440558df73e10564b3 to your computer and use it in GitHub Desktop.
Check if one or all TLDs are available for your domain
#!/bin/bash
#
# Script by Parker Thomas (@Castlecorp)
# /$$$$$$$ /$$$$$/$$$$$$$$
# | $$__ $$|__ $|__ $$__/
# | $$ \ $$ | $$ | $$
# | $$$$$$$/ | $$ | $$
# | $$____/$$ | $$ | $$
# | $$ | $$ | $$ | $$
# | $$ | $$$$$$/ | $$
# |__/ \______/ |__/
#
# Search for open domain names
#
# boilerplate c/o @xero
#-----------------------------------------------------------------------------
# helper functions
#-----------------------------------------------------------------------------
# update this function to gracefully cleanup execution
clean_exit() {
# grab real error code
err=$?
# reset traps for all signals to not interrupt destructor logic
trap '' EXIT HUP INT QUIT PIPE TERM
# add calls to any cleanup functions here
clean_tempfiles
# exit with the appropriate code
exit $err
}
# update this handler to match your options
usage() {
me="$(basename "$(test -L "$0" && readlink "$0" || echo "$0")")"
printf "usage: %s <DOMAIN> [-t|-m|-j]" "$me"
echo " <DOMAIN>: string to use as the domain name"
echo " -t: a single TLD to check"
echo " -m: Machine readable - only output available domains"
echo " -j: Number of jobs to run in parallel. Default is 3"
}
# check if required commands/bins exist
function installed() {
builtin type -P "$1" &> /dev/null
# shellcheck disable=SC2181
[[ $? -ne 0 ]] && return 1
if [[ $# -gt 1 ]]; then
shift # we've just checked the first one
installed "$@"
fi
}
function requirements() {
installed "$@" || {
for dep in "${deps[@]}"
do
if ! command -v "$dep" > /dev/null; then
echo "$dep is not installed."
fi
done
exit 1;
}
}
# main application logic
#-----------------------------------------------------------------------------
function checkArgs() {
# Set required domain arg
if [ $# -lt 1 ]; then usage; fi
NAME="$1"
shift
# Set defaults
MACHINE_READABLE=false
JOBS=3
# Parse optional flags
while getopts 'tmj' opt; do
case "$opt" in
t)
TLDs=$2
shift 2
;;
m)
MACHINE_READABLE=true
shift
;;
j)
JOBS="$3"
;;
*)
usage
;;
esac
done
}
# Download TLDs and save to a tempfile for reference
function getTLDs() {
TLDs=$(mktemp /tmp/TLDs.XXXX)
curl -s https://data.iana.org/TLD/tlds-alpha-by-domain.txt | tail -n +2 >> "$TLDs"
}
# Parameters: domain name and TLD
function resolveDomain() {
local name=$1
local ending=$2
local domain="$name"."$ending"
# Grep the whois result to see if it is taken
if whois "$domain" | grep -Eq \
'^No match|^NOT FOUND|^Not fo|AVAILABLE|^No Data Fou|has not been regi|No entri'
then # Not taken -> echo it
echo "$domain"
fi
}
# If we made a tempfile, rm it
function clean_tempfiles() {
if [ -f "$TLDs" ]; then rm -f "$TLDs"; fi
}
# Main loop
function main() {
deps=("whois" "curl" "parallel")
requirements "${deps[@]}"
checkArgs "$@"
if [ -z "$TLDs" ]; then getTLDs; # If a TLD isn't specified, get the full list
else
RESULT=$(resolveDomain "$NAME" "$TLDs") # If a TLD is specified, just check that one domain
if [ -z "$RESULT" ]; then echo "Domain not available"; else echo "$NAME.$TLDs is available"; fi
clean_exit
fi
if [ "$MACHINE_READABLE" == "false" ]; then echo "Available domains:"; fi
export -f resolveDomain # Allow the resolveDomain function to be used by parallel
parallel --jobs "$JOBS" resolveDomain "$NAME" ::: "$(cat "$TLDs")" # Run resolveDomain on all TLDs `multithreaded`
clean_exit
}
# runtime setup
#-----------------------------------------------------------------------------
# fail fast w/ proper exit codes
set -eo pipefail
# global error handler
trap clean_exit EXIT HUP INT QUIT PIPE TERM
# Run it
main "$@"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment