如何在awk中高效生成指定长度的随机字母数字字符串
需求:在awk内部按需快速生成指定长度的非加密级随机字母数字字符串
Ruby实现参考
Ruby中可以这样实现随机字符串生成:
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 # 达到最小长度时退出循环 rtr[0...len] end (0..5).each{|_| puts rand_string(20)}'
该Ruby代码生成100万个唯一字符串耗时约9秒。
awk初始实现的问题
尝试用awk实现时,初始代码因每次调用函数都使用相同种子,导致生成的字符串完全相同:
awk -v r=$RANDOM ' # r值仅在每次awk调用时作为新种子,而非每次函数调用时更新 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)}}'
输出结果全部重复:
D65CsI55zTsk5otzSoJI D65CsI55zTsk5otzSoJI D65CsI55zTsk5otzSoJI D65CsI55zTsk5otzSoJI D65CsI55zTsk5otzSoJI
基于/dev/urandom的awk实现(速度受限)
改用读取/dev/urandom结合od命令的方法可以正常生成随机字符串,但速度极慢,仅适用于生成少量字符串:
awk ' function rand_string(i) { arg=i*4 cmd="od -A n -t u1 -N " arg " /dev/urandom" # 符合POSIX标准 # ^ ^ 无符号字符 # ^ ^ 读取i*4字节数据 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) }'
输出结果符合预期:
sYY195x6fFQdYMrOn1OS 9mv7KwtgdUu2DgslQByo LyVvVauEBZU2Ad6kVY9q WFsJXvw8YWYmySIP87Nz AMcZY2hKNzBhN1ByX7LW
改进方案的要求
需要修改上述awk代码以满足:
- 兼容多数平台(基于默认POSIX工具集)
- 可快速生成指定长度的合理随机字符串
此前相关问题的解决方案均存在不足:
- 依赖外部工具,速度过慢
- 仅生成随机整数,未正确使用
srand - 依赖shell管道,速度慢且仅适用于Linux
内容的提问来源于stack exchange,提问作者dawg
相关产品推荐
相关产品推荐

