我正在尝试创建一个密码生成器,生成8-16个字符之间的密码.它还必须包含一个数字和小写和大写字母,以及生成时随机放置在字符串中的一个特殊字符.
目前,我的代码有时会给我一个不符合要求的密码,例如.AOKOKKK@1
(没有小写字母)此外,我还需要帮助才能使特殊符号只在密码中出现一次.我怎样才能解决这个问题?
这是我的代码:
length=$[ 8 +$[RANDOM % 16]]
char=(0 1 2 3 4 5 6 7 8 9 a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z ! @ \# $ % ^ \&)
max=${#char[*]}
for ((i = 1; i <= $length ; i++))do
let rand=${RANDOM}%${max}
password="${password}${char[$rand]}"
done
echo $password
Run Code Online (Sandbox Code Playgroud)
Joh*_*024 11
这保证了一个且只有一个特殊字符,以及至少一个数字,小写和大写字母.要在密码中随机放置这些字符,sort -R
用于在打印密码之前加扰字符的顺序:
#!/bin/bash
choose() { echo ${1:RANDOM%${#1}:1}; }
{
choose '!@#$%^\&'
choose '0123456789'
choose 'abcdefghijklmnopqrstuvwxyz'
choose 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
for i in $( seq 1 $(( 4 + RANDOM % 8 )) )
do
choose '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
done
} | sort -R | tr -d '\n'
echo ""
Run Code Online (Sandbox Code Playgroud)
我们定义了一个便利功能:
choose() { echo ${1:RANDOM%${#1}:1}; }
Run Code Online (Sandbox Code Playgroud)
choose
接受一个参数,一个字符串,并从该字符串中随机选择一个字符.
我们在每个所需类型的字符之一的每行打印一个字符:
choose '!@#$%^\&'
choose '0123456789'
choose 'abcdefghijklmnopqrstuvwxyz'
choose 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
Run Code Online (Sandbox Code Playgroud)我们打印所需的剩余字符数,每行一个字符.这些字符是从数字,小写和大写字母中随机选择的:
for i in $( seq 1 $(( 4 + RANDOM % 8 )) )
do
choose '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
done
Run Code Online (Sandbox Code Playgroud)从上面来看,特殊字符总是第一个,数字第二个,等等.我们需要随机化.我们这样做sort -R
:
sort -R | tr -d '\n'
Run Code Online (Sandbox Code Playgroud)
tr -d '\n'
用于从字符之间删除换行符,从而在一行中生成一串字符.
在评论中,JonathanLeffer表明输出sort -R
并非完全随机. sort -R
对每行的哈希进行排序.显然添加了随机种子,但每行都接收相同的种子.为了解决这个问题,下面的版本在每一行都提供了自己的种子.这是通过更改choose
功能来完成的.最后,awk
用于删除这些数字并显示完整的密码:
#!/bin/bash
choose() { echo ${1:RANDOM%${#1}:1} $RANDOM; }
{
choose '!@#$%^\&'
choose '0123456789'
choose 'abcdefghijklmnopqrstuvwxyz'
choose 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
for i in $( seq 1 $(( 4 + RANDOM % 8 )) )
do
choose '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
done
} | sort -R | awk '{printf "%s",$1}'
echo ""
Run Code Online (Sandbox Code Playgroud)
在awk
,每行分为字段.第一个字段是随机选择的字母,而第二个字段是我们为种子散列添加的随机数.该语句printf "%s",$1
打印第一个字段(没有尾随空格)并忽略第二个字段.最终结果是我们想要的密码.
要将输出捕获到变量,我们使用命令替换:
choose() { echo ${1:RANDOM%${#1}:1} $RANDOM; }
pass="$({ choose '!@#$%^\&'
choose '0123456789'
choose 'abcdefghijklmnopqrstuvwxyz'
choose 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
for i in $( seq 1 $(( 4 + RANDOM % 8 )) )
do
choose '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'
done
} | sort -R | awk '{printf "%s",$1}')"
Run Code Online (Sandbox Code Playgroud)
命令替换,表示为$(...)
,运行parens中的命令并捕获它们的标准输出.