De dentro do awk, quero gerar uma sequência de X caracteres alfanuméricos razoavelmente aleatórios (ou seja, aleatórios, mas não criptográficos) sob demanda e rapidamente.
Em Ruby, eu poderia fazer isso:
ruby -e '
def rand_string(len, min=48, max=123, pattern=/[[:alnum:]]/)
rtr=""
while rtr.length<len do
rtr+=(0..len).map { (min + rand(max-min)).chr }.
select{|e| e[pattern] }.join
end # falls out when min length achieved
rtr[0..len]
end
(0..5).each{|_| puts rand_string(20)}'
Impressões:
7Ntz5NF5juUL7tGmYQhsc
kaOzO1aIxkW5rmJ9CaKtD
49SpdFTibXR1WPWV7li6c
PT862YZQd0dOIaFOIY0d1
vYktRXkdsj38iH3s2WKI
3nQZ7cCVEXvoaOZvm6mTR
Para uma comparação de tempo, o Ruby pode produzir 1.000.000 de strings exclusivas (sem duplicatas) em aproximadamente 9 segundos.
Levando isso em consideração, tentei no awk:
awk -v r=$RANDOM '
# the r value will only be a new seed each invocation -- not each f call
function rand_string(i) {
s=""
min=48
max=123
srand(r)
while (length(s)<i) {
c=sprintf("%c", int(min+rand()*(max-min+1)))
if (c~/[[:alnum:]]/) s=s c
}
return s
}
BEGIN{ for (i=1; i<=5; i++) {print rand_string(20)}}'
Isso não funciona -- mesma semente, mesmo resultado de string. Imprime:
D65CsI55zTsk5otzSoJI
D65CsI55zTsk5otzSoJI
D65CsI55zTsk5otzSoJI
D65CsI55zTsk5otzSoJI
D65CsI55zTsk5otzSoJI
Agora tente ler /dev/urandom
com od
:
awk '
function rand_string(i) {
arg=i*4
cmd="od -A n -t u1 -N " arg " /dev/urandom" # this is POSIX
# ^ ^ unsigned character
# ^ ^ count of i*4 bytes
s=""
min=48
max=123
while (length(s)<i) {
while((cmd | getline line)>0) {
split(line, la)
for (e in la) {
if (la[e]<min || la[e]>max) continue
c=sprintf("%c", la[e])
if (c~/[[:alnum:]]/) s=s c
}
}
close(cmd)
}
return substr(s,1,i)
}
BEGIN {for(i=1;i<=5;i++) print rand_string(20) }'
Isso funciona como desejado. Imprime:
sYY195x6fFQdYMrOn1OS
9mv7KwtgdUu2DgslQByo
LyVvVauEBZU2Ad6kVY9q
WFsJXvw8YWYmySIP87Nz
AMcZY2hKNzBhN1ByX7LW
Mas agora o problema é que o pipe od -A n -t u1 -N " arg " /dev/urandom
está muito lento — inutilizável, exceto para um número trivial de strings.
Alguma ideia de como posso modificar um desses awks para que ele:
- Funciona na maioria das plataformas (ou seja, kit POSIX padrão);
- Pode produzir sequências razoavelmente aleatórias de comprimento X rapidamente.
Esta pergunta já foi feita algumas vezes:
- Como posso substituir uma string por uma string alfanumérica aleatória de 48 caracteres usando o awk onde a resposta é usar ferramentas externas -- muito lento;
- Substitua o padrão fornecido por um aleatório com awk, mas esse é um int aleatório e não usa
srand
; - Execute um comando (para gerar strings aleatórias) dentro do awk , mas novamente use o shell pipe (muito lento) e somente Linux.