Expanding a bit on @Cyrus' answer here's an alternate version I've settled on after dealing with a lot of passwords in a lot of contexts:
# Generate a url safe password.
password() {
local length=${1:-"10"}
cat /dev/urandom | tr -dc A-Za-z0-9~_- | head -c $length && echo
}
This uses only characters that don't need to be url-encoded and that are easy to select and type, and still has about 60 bits of entropy which is plenty for most purposes (I actually use a default length of 20 which has 120 bits of entropy, but I can't make an honest argument that that's necessary for security).
I also have the following:
# Generate a url safe password that:
# - begins with a letter, and has at least
# - one uppercase letter,
# - one lowercase letter,
# - one digit, and
# - one special character.
stupid_password() {
while :
do
local pass=$(password "$1")
[[ $pass != *[~_-]* ]] && continue
[[ $pass != [A-Za-z]* ]] && continue
[[ $pass != *[A-Z]* ]] && continue
[[ $pass != *[a-z]* ]] && continue
[[ $pass != *[0-9]* ]] && continue
echo "$pass"
break
done
}
The filtering process is inefficient, but still essentially instantaneous. The passwords are less secure, but will work on websites that haven't read the NIST guidelines on password complexity