Один в awk:
awk '{
for(i=1;i<=length();i++) { # read a line, iterate chars
chr=substr($0,i,1) # get a char
if(chr~/[a-z]/&&(a<=2||((b>=1)&&(c>=1)&&(d>=1)))) { # if in char class a-z
str=str chr # append
a++ # keep count to get
} # ... from each class
if(chr~/[A-Z]/&&(b<=2||((a>=1)&&(c>=1)&&(d>=1)))) {
str=str chr
b++
}
if(chr~/[0-9]/&&(c<=2||((a>=1)&&(b>=1)&&(d>=1)))) {
str=str chr
c++
}
if(chr~/[$%&]/&&(d<=2||((a>=1)&&(b>=1)&&(c>=1)))) {
str=str chr
d++
}
if(length(str)==12) {
print str
exit
}
}
}' /dev/urandom
Поскольку классы символов не имеют одинаковый размер, и только 3 допускается для каждого класса, прежде чем будут представлены все классы, случайное число, вероятно, смещено.
Этот получает принятые символы из /dev/urandom
(ну, он читается из файла, поэтому, куда бы вы ни указали), и 'печатайте все совпадения, пока вы не нажмете Ctrl- c:
awk '{
for(i=1;i<=length();i++) {
chr=substr($0,i,1)
if(chr~/[a-zA-Z0-9$%&]/)
str=str chr
}
if(length(str)<12)
next
else
for(i=1;i<=length(str)-11;i++) {
sstr=substr(str,i,12)
if(sstr~/[a-z]/ && sstr~/[A-Z]/ && sstr~/[0-9]/ && sstr~/[$%&]/){
print substr(str,i,12)
i+=11
}
}
str=""
}' /dev/urandom