Aqui estão algumas abordagens:
1. Iterar até obter uma senha que você "goste"
while true
do
word=$(tr -cd "[:graph:]" < /dev/urandom | head -c ${1:-32})
if [[ "$word" =~ [[:punct:]].*[[:punct:]] ]]
then
echo "$word has multiple special characters - reject."
continue
fi
if [[ "$word" =~ [[:punct:]] ]]
then
echo "$word has one special character - accept."
break
fi
echo "$word has no special characters - reject."
continue
done
Aviso: isso pode levar muito tempo para um grande número de caracteres (por exemplo, > 16).
2. Pare depois de receber um caractere de pontuação
n=${1:-32}
if [ "$2" == "0" ]
then
CHAR="[:alnum:]"
else
CHAR="[:graph:]"
fi
word=
for ((i=0; i<n; i++))
do
thischar=$(tr -cd "$CHAR" < /dev/urandom | head -c 1)
if ! [[ "$thischar" =~ [[:alnum:]] ]]
# Probably equivalent to if [[ "$thischar" =~ [[:punct:]] ]]
then
# Got one special character – don’t allow any more.
echo "$thischar is a special character."
CHAR="[:alnum:]"
fi
word="$word$thischar"
done
echo "$word"
Observe que isso recebe o caractere especial nos três primeiros
(por exemplo, ab!defghijklmnopqrstuvwxyz123456
) muito com frequência.
Além disso, é teoricamente possível obter uma senha sem caracteres especiais
usando essa abordagem.