生成许多随机字母数字字符串

问题描述 投票:0回答:1

从 awk 的inside,我想根据需要快速生成一串 X 字母数字字符,合理随机(即随机但不是加密)。

在 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                     # falls out when min length achieved 
    rtr[0..len]
end

(0..5).each{|_| puts rand_string(20)}'  

打印:

7Ntz5NF5juUL7tGmYQhsc
kaOzO1aIxkW5rmJ9CaKtD
49SpdFTibXR1WPWV7li6c
PT862YZQd0dOIaFOIY0d1
vYktRXkdsj38iH3s2WKI
3nQZ7cCVEXvoaOZvm6mTR

作为时间比较,Ruby 可以在大约 9 秒内生成 1,000,000 个唯一字符串(无重复)。

考虑到这一点,我在 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)}}'

这是行不通的——相同的种子,相同的字符串结果。打印:

D65CsI55zTsk5otzSoJI
D65CsI55zTsk5otzSoJI
D65CsI55zTsk5otzSoJI
D65CsI55zTsk5otzSoJI
D65CsI55zTsk5otzSoJI

现在尝试用

/dev/urandom
来阅读
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) }'

这按预期工作。打印:

sYY195x6fFQdYMrOn1OS
9mv7KwtgdUu2DgslQByo
LyVvVauEBZU2Ad6kVY9q
WFsJXvw8YWYmySIP87Nz
AMcZY2hKNzBhN1ByX7LW

但现在的问题是管道

od -A n -t u1 -N " arg " /dev/urandom
真的很慢——除了少量的字符串之外无法使用。

知道如何修改其中一个 awks 以便它:

  1. 在大多数平台上运行(即默认的 POSIX 套件);
  2. 可以快速产生X长度的合理随机字符串。

这个问题已经被问过几次了:

  1. 如何使用 awk 将字符串替换为长度为 48 个字符的随机字母数字字符串,答案是使用外部工具——太慢了;
  2. 用 awk 用随机模式替换给定模式,但这是一个随机 int 并且不使用
    srand
    ;
  3. 在 awk 中执行命令(生成随机字符串),但再次使用 shell 管道(太慢)并且仅限 Linux。
bash function random awk
1个回答
0
投票

使用 awk 1 并执行以下操作:

time awk -v r=$RANDOM '
function rand_string(i) {
    s=""
    min=48
    max=123
    #srand(res) Duh!! WRONG! Only use srand once or it resets to the same sequence
    while (length(s)<i) {
        c=sprintf("%c", int(min+rand()*(max-min+1)))
        if (c~/[[:alnum:]]/) s=s c
    }
    return s
}
BEGIN{ 
    srand(r)      # Use srand ONCE only
    for (i=1; i<=1000000; i++) {print rand_string(20)}
}'  | uniq -c | awk '$1>1'

# No output so no duplicates
real    0m9.813s
user    0m10.413s
sys 0m0.074s

VS 红宝石:

time 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..1_000_000).each{|_| puts rand_string(20)}' | uniq -c | awk '$1>1'

# no output so no duplicates

real    0m12.954s
user    0m13.441s
sys 0m0.217s

Ruby 的时间增加可能是管道的剩余部分,这与 awk 相同。所以 awk 更快一点...

© www.soinside.com 2019 - 2024. All rights reserved.