Skip to content

Instantly share code, notes, and snippets.

@skull-squadron
Last active August 12, 2025 11:00
Show Gist options
  • Select an option

  • Save skull-squadron/aa37d6706503fd2fdc0dcd162f6719e5 to your computer and use it in GitHub Desktop.

Select an option

Save skull-squadron/aa37d6706503fd2fdc0dcd162f6719e5 to your computer and use it in GitHub Desktop.
Generate a random password of length N meeting complexity requirements in pure Bash 4+
#!/usr/bin/env bash
set -Eeuo pipefail
die() {
echo >&2 "$@"
echo >&2
echo >&2 "Usage: $(basename "$0") {{length>=1}} {{char_range[:min] ...}}"
echo >&2
echo >&2
exit 1
}
random_chars() {
head /dev/random | LC_ALL=C tr -dc "$1" | head -c "$2"
}
length="${1-}" total_min=0 rest_charset='' r=
if (($# < 2)) || [[ ! "$length" =~ ^[1-9][0-9]*$ ]]; then
die 'Must specify length >= 1 and at least one character range'
fi
shift
# Parse ranges and minimum requirements
for arg in "$@"; do
if [[ "$arg" =~ .+:[0-9]+$ ]]; then
min=${arg##*:} charset=${arg%:*}
if ((min == 0)); then
rest_charset+="$charset"
else
r+="$(random_chars "$charset" "$min")"
((total_min += min))
fi
else
rest_charset+="$arg"
fi
done
rest_length=$((length - total_min))
if ((rest_length < 0)); then
die "Sum of minimum requirements ($total_min) exceeds password length ($length)"
elif ((rest_length > 0)); then
[[ "$rest_charset" ]] || die 'One or more character ranges must be specified without :N to generate remaining characters'
r+=$(random_chars "$rest_charset" "$rest_length")
fi
# shuffle the result
for ((i = ${#r}; i > 0; i--)); do
j=$((SRANDOM % i))
echo -n "${r:$j:1}"
r="${r:0:j}${r:j+1}"
done
echo
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment