Linux 上可以使用一行命令批量生成随机字符串:
cat /dev/urandom | LC_ALL=C tr -dc "[:graph:]" | fold -w 16 |head -100
这个命令组合主要用于生成一个随机的、包含可打印字符(不包括空格)的字符串列表,每个字符串长度为16个字符,总共生成100个这样的字符串。下面是对命令各部分的详细解析:
- cat /dev/urandom:
- cat 命令用于读取文件内容并将其输出到标准输出。
- /dev/urandom 是一个特殊的设备文件,提供了无限长度的伪随机数据流。与 /dev/random 相比,/dev/urandom 不会因缺少熵(随机性)而阻塞输出,但它可能包含较少的随机性。
- | LC_ALL=C tr -dc "[:graph:]" |:
- 管道符号 | 用于将前一个命令的输出作为后一个命令的输入。
- LC_ALL=C 设置环境变量 LC_ALL 为 C,这通常用于确保命令的行为在不同的语言环境中保持一致。特别是,它影响字符分类(如哪些字符是“可打印的”)。
- tr -dc "[:graph:]" 使用 tr(translate 或 delete/complement)命令。-d 选项删除(实际上是忽略)输入中不匹配给定集合的字符,-c 选项是取补集的意思,即删除集合外的所有字符。[:graph:] 是一个字符类,表示所有可打印字符(除了空格)。因此,这个命令的作用是从 /dev/urandom 的输出中筛选出所有可打印字符(不包括空格)。
- | fold -w 16 |:
- 再次使用管道将前一个命令的输出作为输入。
- fold -w 16 命令用于将输入文本折叠成每行宽度为16个字符的段落。在这个上下文中,它确保每个生成的随机字符串长度为16个字符。
- head -100:
- 最后,head -100 命令从折叠后的输出中取出前100行。由于每行都是一个长度为16的随机字符串,因此最终结果是100个这样的字符串。
综上所述,这个命令组合的作用是生成一个包含100个随机字符串的列表,每个字符串由16个随机选择的可打印字符(不包括空格)组成。这样的字符串可以用于各种需要随机标识符的场合,如密码生成、测试数据生成等。
但是,如果要求密码中必须包含数字、大小写字母、特殊字符,那么这条命令的结果并不是每次都符合要求。创建内容如下的脚本文件 GenerateStrongPassword.sh:
#!/bin/bash
if [ ! -n "$1" ] ;then
echo "执行方式:GenerateStrongPassword.sh 密码个数"
exit
fi
is_positive_integer() {
# 正则表达式判断是否为正整数
regex='^[0-9]+$'
if [[ $1 =~ $regex ]] && [ "$1" -ge 0 ]; then
return 0
else
return 1
fi
}
# 调用函数检查参数是否为正整数
if !(is_positive_integer "$1") then
echo "参数必须是正整数"
exit
fi
num=1
password=`cat /dev/urandom | LC_ALL=C tr -dc "[:graph:]" | fold -w 16 | head -$1`
regexp_str='^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^a-zA-Z0-9]).{16}$'
for i in $password
do
if grep -oP $regexp_str <<< $i; then
:
else
echo "$i $((num++))"
fi
done
执行脚本生成 100 个密码,结果如下:
[root@vvml-yz-hbase-test~]#./GenerateStrongPassword.sh 100
6t&)KjX&'v/]6OgF
@evZ^G{5,}&e,j\.
!X&VG.YYi6eXzuSj
P3q=P2u_%:G$"uY8
LiQ|`1iYF!,;:t%i
v(CiR[,]PNY}z<D5
2D=J0N,]fac_@Z\s
H!:k*Kvj+WbzqVng 1
*^(Lt+`vY0+#jpG,
w03dsuQx4dRK1-F4
dG^|Y[:Mp?L/(fG= 2
gZLm,:>=e&q4nrJe
9a+rx&e_TO;)BzW/
Q}yQY%gS-}T9T<<2
$sbs*i1q?tm`EcmE
ua!blnpcER"d7F[_
$K.z/MDf=<~J3V!F
Cs'pYR%|5%aXm4Ja
V)!x0qU.ORtB#vDH
OD5;^Sl@ruqZ9!(U
}P`X9\F^13YxR(hL
p@?>acOQ\~WY=E!$ 3
bt7s[N?{E_!zy.L-
ZPwTb#]0j/VC%N4@
p3j+X86d|u>$#aTM
RjYUcJ8%{l4&>ST|
vA|=WgfljDhi?clg 4
COjkZYDww16r9CHS 5
YDhf:B%L+[7E|O]]
yj@p$O`M4$G6yvnQ
=_`p!MLXF7]nm>v'
@ao]vs\izFQ'D[+q 6
Ck!]IA'>o-$`2ye(
`^(V{iTRNzBB20\C
U]<ayX6J'}G(!Lkk
U=yx*rb4oWKa|o&x
zVH\Z5TG{2JH>Q1e
m1)&^}A_[@Z_=sA[
fH!(>SX"j#^54w+N
,5y@`q#+&B\duw$=
w}XS;RA.zvg$X961
Otv8#?mI^Q+P<k[p
!~~+5{~OV1$[=mY6
g|8*X+ej1kSTLSrp
T<vt%[P!>}cD(sG= 7
&lWpH~e.s'(A)xjd 8
DlSM>\h.vOVNR!uq 9
cUg0~u?WLzFl!}]'
*+mnW=XE<eexuxMt 10
324]zMD:0`cKH6_Q
d@)YW}%:et2{qWPr
IKil*my<MLkS6$H7
v0Qh|pSWDQUrhQ9H
M2g9aZCM?;<B68|*
6C?nD?[S(0S-r3o=
oML/&z41b3yTP$`5
bd4]b/{2eS(RTylU
<g24mIW;$uuIdz=/
G|ro,?JKHNBsvJqZ 11
P)lv[V{
{<y91odt{
J[H3R)<x^u9]>nL$
W`f6yB|'WAlPpy&P
C>*yDPvN^uwr(Hun 12
Q!~GP|,PY`Cu1h!G
a(HA3.WTiHd|)Sw?
I-nrZn{Kuo<]Jqer 13
K~h5LlM.^/8``o6s
)^TUjQBb+P&ehF_T 14
P_3YF%'GcHM"4IG1
YDHSP?pL+x[t]w)e 15
}iiF6VL?aLPPipOf
){FOr03.O,2y4sRC
QN>#RF(VEZ9}e$Ki
/C#t^/v\XZ0~IiQ.
z7+7:*uivHuh+,%k
.Px~gxZ\UE|G"7*l
Os<fc.WZ=i*fTZe# 16
\%FFabpNq#WP#v6&
Y%p'y9N:M30Bh;G^
rlu=LeuKZ.9oyuRJ
~L"V33aBXF@76Gp6
=pKJ:tvg'|teoUJ9
>RL.))?\Rax@lTq# 17
lE+^s;NiS(z3|wIe
U,ss]R7`dJ<}w$YG
Mq'nMF6+Rn~UN:A.
7=AAZ6To=,=cQdD#
BhF}Adl/9qlNk=,a
*HvGQ$[Se]-)o(Sy 18
O9-4quTrWt@f)bSI
-Iz(W">_s+xjy<mY 19
,EU0YBHWE]^5xoG}
">W<j\y,Z,Ia_F9d
EnK{CP\A]8|ETY'0
k!WbYe~18qwr"s%M
PCb'/y\3Q?W>jSk@
Mx%D?2XcF5C$wGCx
Kl+~htGD&5Rp!O.s
qy5ZV("I7>*K2.Ux
qD<&h()(\%N[X1Z%
[root@vvml-yz-hbase-test~]#
脚本中使用正则表达式对生成的密码进行判断。
- 正则表达式说明:
-
^ 代表开始。
-
(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^a-zA-Z0-9]) 用四个肯定顺序环视零宽断言对字符进行判定。
-
(?=.*[a-z]) 判断小写字母是否存在。
-
(?=.*[A-Z]) 判断大写字母是否存在。
-
(?=.*[0-9]) 判断数字是否存在。
-
(?=.*[^a-zA-Z0-9]) 判断特殊字符是否存在。
-
.{16} 代表任意 16 个字符。
-
$ 代表结尾。
-
可以看到,有 19 个密码不满足要求,其中 18 个不包含数字,一个不包含特殊字符(第5个)。经过多次测试,约有 10% - 20% 会出现这种情况。下面修改脚本,批量生成强密码,具体需求如下:
- 批量生成 100 个密码。
- 密码长度统一为 16 个字符。
- 密码中包含数字、大小写字母、特殊字符。
主要做的修改是:当判断生成的密码不符合要求时重新生成一个,继续判断,直到满足要求为止。修改后的脚本内容如下:
#!/bin/bash
if [ ! -n "$1" ] || [ ! -n "$2" ] ;then
echo "执行方式:GenerateStrongPassword.sh 密码长度 密码个数"
exit
fi
is_positive_integer() {
# 正则表达式判断是否为正整数
regex='^[0-9]+$'
if [[ $1 =~ $regex ]] && [ "$1" -ge 0 ]; then
return 0
else
return 1
fi
}
# 调用函数检查参数是否为正整数
if !(is_positive_integer "$1") || [ $1 -lt 8 ]; then
echo "密码长度必须是大于等于 8 的整数!"
exit
fi
if !(is_positive_integer "$2") then
echo "密码个数必须是正整数!"
exit
fi
num=1
password=`cat /dev/urandom | LC_ALL=C tr -dc "[:graph:]" | fold -w $1 | head -$2`
regexp_str="^(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])(?=.*[^a-zA-Z0-9]).{"$1"}$"
for i in $password
do
if grep -oP $regexp_str <<< $i > /dev/null ; then
echo "$i 强密码"
else
a=`cat /dev/urandom | LC_ALL=C tr -dc "[:graph:]" | fold -w $1 | head -1`
b=1
until echo "$a" | grep -oP $regexp_str > /dev/null
do
a=`cat /dev/urandom | LC_ALL=C tr -dc "[:graph:]" | fold -w $1 | head -1`
((b++))
done
echo "$a 重新生成的强密码 $((num++)) $b"
fi
done
执行脚本结果如下:
[root@vvml-yz-hbase-test~]#./GenerateStrongPassword.sh 100
Us7xIAV3"Zx%/q+, 强密码
jcP$S]iRFw-IR%39 强密码
-,|-Rf3%YD\iTP*; 强密码
=5ZgY7wz\cNN-1:+ 重新生成的强密码 1 1
5|'1|,fa04'S3T:U 强密码
KWh8^;mxQ2_[|+AQ 强密码
Nc3P_5a_G7c2LTBU 强密码
s<~z'Ecki/iY~5)F 强密码
@?P>:kQ,36EqUkBc 强密码
vPEabq4rm;P)R)&$ 强密码
'xX!c2y^OFU("1.k 强密码
Bvw\rpEE}1$bHVp' 强密码
`*}XS\|'iFs`n#\8 强密码
D|#ZJ$*~&0}rpZqL 强密码
uLo'^h\MjLM6-=F) 强密码
sy[hHS}_/mEN4{)s 强密码
b9o{N[sFv1\qm+ng 重新生成的强密码 2 2
gU$Yd=`F59*2$4++ 强密码
K[_oHT}=+xvnZ$o3 重新生成的强密码 3 1
J\1{3.2`K^hs!A5F 重新生成的强密码 4 1
2"'/,J`NR5zbm=_M 强密码
z6yl3|+DM4V<vVvj 强密码
>ZDwl6kh0J&r0rnh 强密码
&2"l#3f-JP,[QV$@ 强密码
!53nJ9Mj%v5;}P;N 强密码
tq"87J_&T1<Ao<3E 重新生成的强密码 5 1
T;).usjjP)9drnAf 强密码
Nx<o^<S1ra]L:2~+ 强密码
Vk;@B>kJ8gTtd~PM 强密码
Tij,*\(iWi/Wv7Hd 强密码
p3==yEOE^;`CmX/l 强密码
`;K;Z)=d&T17:o~l 强密码
=GvqRXp&DtF4rXB6 强密码
0ze_8.ulk(&m{<,J 强密码
\`=)et>nMYF6-A;~ 强密码
I:mBDp0qVF/`rib0 强密码
dA|]7u,Y%o[jnw9h 强密码
FN3EM1XSMf@>(kAF 强密码
yN.$T-43RLniG8z; 重新生成的强密码 6 2
Q]HFKP@GcvOY6*9= 重新生成的强密码 7 1
r.-@Pnzv^6=vnJn. 强密码
lM^Y%cq,MSM-B1U( 强密码
W80})~=zciH&~O#g 强密码
5TAz)J0|DO3dA7AS 强密码
$0%988qdYDYl|>m# 强密码
%IqT*j/%24NgtNn6 重新生成的强密码 8 1
4lJp\p1&X{ES{}_{ 强密码
X1@<J"EOuA3GDk~w 强密码
q6#,8MccDjR{-y/[ 强密码
'Cs=H&S)o)7&W`xx 强密码
j7n2J"+8"^]#siJ} 强密码
(Iqw8v[hq%J%rJh+ 强密码
(sg;5ixHI?hj.5$L 强密码
B/:7('##QlE]I{&U 重新生成的强密码 9 1
iViKqak1RMnD%E2^ 强密码
3rKXpfpyB=TH'E9" 强密码
"^UR~y3W7}IE6^|V 强密码
`A&izGYlj78zhiSL 重新生成的强密码 10 1
jBFvI'ZpiI%[b62G 强密码
r=r)6.gHH=Z#nYn$ 强密码
'f>6T9z"=fX,[Yp= 强密码
PjC?Pt2k6QJkP!/` 强密码
96Df_e_>DBj<nf~Q 强密码
L,u^#868"Ng2g9@$ 强密码
K|#>dPCJc<Di7)uT 强密码
xp+#_[iQ!i50664A 强密码
hN`Q+47yg<"{:Xh& 强密码
&lZ={Q8bj[=lh3_H 强密码
Wn1<V=a}k-UL?dk} 重新生成的强密码 11 1
JGFp4RO/0-w>@Xl+ 强密码
YUO%x,O>-VL1xBj, 强密码
5=sYKIg&v3I3}CHo 强密码
?Qu5Q47!l|r[=[^; 强密码
n^h9=ng"_GM3~8r4 重新生成的强密码 12 1
NWJ/(O4{j%gj].91 强密码
->!yXeIler_}8_<C 强密码
K`=72Ybxai_\Dgwl 强密码
6>i<(EM2<c)Wjq.Q 强密码
_(If!zM;hh9.KbqZ 强密码
4Mne#C8*4Bc!P@BX 强密码
664P>o6?[)ht8`:H 强密码
{?3MmCh_j`Bhcb/j 强密码
@0.wTK,()/`@u;AA 强密码
B-zC_\C3t!P$*eL5 强密码
tHtI@%&7h*zxGe(\ 强密码
LA9JtMs@({hr;c`o 强密码
j/W:Ie8J#0<R{lJy 强密码
QncC]S2-7(63ZLhf 强密码
1>y_$OQ3F)Z;aw)] 强密码
;VsQO^$H-0mt{h|' 强密码
*HaQmJ0MQ'~1AYcq 强密码
W>p!8I/sd:%RjS3b 强密码
~I5iv\jY_N;@p\%d 重新生成的强密码 13 1
Y3+@0G"|^zpkZ`}6 强密码
L0]'k,HIA^k]BQ]j 强密码
I"S<OQz-G,9$$mNv 强密码
]V5D-BX?NOWm/%lI 强密码
Ba^T3.eslN>*c184 重新生成的强密码 14 1
nnY5orqh!v8zU./> 强密码
$>szx_N).Vy2x!wO 强密码
[root@vvml-yz-hbase-test~]#
可以看到,所有 100 个密码都为强密码,完全满足需求。因为不满足需求的情况不到 20%,所以不用担心循环陷入无休止的迭代中。本例最初生成的 100 个密码中,有 14 个需要重新生成强密码,其中只有两个重新生成了两次,其它 12 个都是只重新生成一次即满足要求。当然必须指出,这版实现使用的是“判错重来”方式,会有不到 20% 的密码生成是做了无用功。
文章评论