如何在Bash中生成随机数?

woa*_*kas 191 random bash shell

如何在Bash中生成一个范围内的随机数?

Nel*_*son 231

使用$RANDOM.它通常与简单的shell算法结合使用.例如,要生成1到10之间的随机数:

$ echo $((1 + RANDOM % 10))
3
Run Code Online (Sandbox Code Playgroud)

实际的发电机在variables.c,功能brand().旧版本是一个简单的线性发电机.版本4.0 bash使用了一个引用 1985年论文的生成器,这可能意味着它是伪随机数的合适来源.我不会将它用于模拟(当然也不用于加密),但它可能足以用于基本脚本编写任务.

如果您正在做一些需要严重随机数的事情,您可以使用/dev/random或者/dev/urandom如果它们可用:

$ dd if=/dev/urandom count=4 bs=1 | od -t d
Run Code Online (Sandbox Code Playgroud)

  • 通过模拟你的随机输入,你是"[pigeon-holing](http://en.wikipedia.org/wiki/Pigeonhole_principle)"的结果.由于`$ RANDOM`的范围是'0-32767`,数字'0`-`7`映射到'3277`不同的可能输入,但是'8`和`9`只能以不同的方式产生`3276`(因为`32768`和'32769`是不可能的).这对于快速黑客来说是一个小问题,但意味着结果不是一成不变的.随机库,如Java的"Random",提供了在给定范围内正确返回均匀随机数的函数,而不是简单地修改一个不可分割的数字. (43认同)
  • 这里要小心.虽然这在捏合时很好,但对随机数进行算术会显着影响结果的随机性.在$ $ RANDOM%10`的情况下,即使`$ RANDOM`是随机数据的强大来源,8和9也可测量(尽管略有)可能性小于0-7. (16认同)
  • 在`(())`中,你可以跳过变量的前缀`$`,比如`$((1 + RANDOM % 10))`。 (13认同)
  • 仅就上下文而言,%10的基本代表意味着8和9比0-7低约0.03%.如果您的shell脚本需要更准确的统一随机数,那么请务必使用更复杂和正确的机制. (9认同)
  • @ dimo414我好奇地"勉强",你有一个我可以找到更多相关信息的来源吗? (3认同)

And*_*are 68

请看$RANDOM:

$RANDOM 是一个内部Bash函数(不是常量),它返回0到32767范围内的伪随机整数.它不应该用于生成加密密钥.

  • @JinKwon`32767`是"2 ^ 16/2 - 1",这是有符号16位整数的上限. (12认同)
  • @BrettHolman我认为他试图指出签名的16位整数的"签名"部分.2 ^ 16个值,分为正和负的一半. (8认同)
  • @JinKwon你能澄清一下为什么你不说它是“2^15 - 1”吗?这是等效的,所以我只是好奇是否缺少一些上下文? (5认同)
  • “32767”有什么特殊含义吗? (3认同)
  • 那么范围不应该是-32768到32767吗? (3认同)

Bar*_*run 35

从你的shell尝试这个:

$ od -A n -t d -N 1 /dev/urandom
Run Code Online (Sandbox Code Playgroud)

这里,-t d指定输出格式应该是十进制的; -N 1说要从中读取一个字节/dev/urandom.

  • 你可以删除空格:`od -A n -td -N 1/dev/urandom | tr -d''` (9认同)
  • 该问题要求范围内的数字. (2认同)

kni*_*wim 31

您也可以使用shuf(coreutils中提供).

shuf -i 1-100000 -n 1
Run Code Online (Sandbox Code Playgroud)

  • 默认情况下,“shuf”不使用加密安全的伪随机数生成器,但可以将“shuf”与“/dev/urandom”(“--random-source”选项)一起使用。相关:https://unix.stackexchange.com/a/705633/133353(*默认情况下,这些命令使用初始化的内部伪随机生成器*...) (5认同)
  • 据我了解,这些数字不是随机的。如果您指定“shuf -i 1-10 -n 10”,您将获得从 1 到 10 的所有数字,并且恰好为 1。如果您指定“-n 15”,您仍然只会获得这 10 个数字一次。这实际上只是洗牌,而不是生成随机数。 (3认同)
  • 要获得带有替换的随机数:-r (3认同)
  • 我更喜欢这个选项,因为使用“-n”很容易生成 N 个随机数。例如 *生成 5 个 1 到 100 之间的随机数*:`shuf -i 1-100 -n 5` (2认同)

gho*_*g74 20

你也可以从awk获得随机数

awk 'BEGIN {
   # seed
   srand()
   for (i=1;i<=1000;i++){
     print int(1 + rand() * 100)
   }
}'
Run Code Online (Sandbox Code Playgroud)

  • 感谢您提供包括播种的解决方案。我在任何地方都找不到! (2认同)
  • +1进行播种。值得一提的是`srand()`的种子是当前的CPU时间。如果需要指定特定的种子,以便可以复制RNG,请使用“ srand(x)”,其中“ x”是种子。同样,引自GNU awk的数字功能手册,“不同的awk实现内部使用了不同的随机数生成器。” 结果是,如果您对生成统计信息分布感兴趣,则应该期望在不同平台上从一个运行时到下一个运行时之间都有细微的变化(所有运行时都是awk或gawk)。 (2认同)

Ant*_*val 18

有$ RANDOM.我不确切知道它是如何工作的.但它的确有效.对于测试,您可以:

echo $RANDOM
Run Code Online (Sandbox Code Playgroud)

  • @ghost21blade `$(( ($RANDOM % 10) + 1 ))` (2认同)

Dav*_*omb 11

0到9之间的随机数.

echo $((RANDOM%10))
Run Code Online (Sandbox Code Playgroud)

  • 什么?它仍然会在 0 到 9 之间,尽管 8 和 9 的发生概率比 0 到 7 稍低,如另一个答案中所述。 (3认同)
  • 我不好,没有正确阅读手册页。$ RANDOM仅从0到32767。它应该说“随机数通常在1到3之间,并且有一些边锋”;) (2认同)

fra*_*aff 11

我喜欢这个技巧:

echo ${RANDOM:0:1} # random number between 1 and 9
echo ${RANDOM:0:2} # random number between 1 and 99
Run Code Online (Sandbox Code Playgroud)

...

  • 如果您使用最后一位数字,它会相当不错,但它会包含 0 和 00。在单个数字上,0-7 比 8-9 出现的频率高 0.03%。在 2 位数字上,0-67 比 68-99 出现的频率高 0.3%。如果你需要一个好的随机数分布,希望你没有使用 bash。与原来的:`${RANDOM:0:1}` 有 67.8% 的机会给你 1 或 2,`${RANDOM:0:2}` 只有 0.03% 的机会给你个位数数字(应该是 1%),并且两者都有 0.003% 的机会给你一个 0。仍然有一些用例很好(例如不一致的输入)。 (5认同)
  • $ RANDOM的范围是0-32767。与4-9相比,最终以1、2或3开头的数字更多。如果您可以接受分配不平衡的情况,则可以正常使用。 (2认同)
  • @jbo5112 你说得对,显示最后一位呢?echo ${RANDOM:0-1} 一位数字,${RANDOM:0-2} 两位数字......? (2认同)

ogu*_*ail 10

bash 5.1引入了一个新变量 ,SRANDOM它从系统的熵引擎中获取随机数据,因此不是线性的,不能重新播种以获得相同的随机序列。这个变量可以用来代替RANDOM生成更多的随机数。

$ echo $((1 + SRANDOM % 10))
4
Run Code Online (Sandbox Code Playgroud)


Roe*_*aar 9

我就此写了几篇文章。

$ RANDOM=$(date +%s%N | cut -b10-19 | sed 's|^[0]\+||')
$ echo $(( $RANDOM % 113 + 13 ))
Run Code Online (Sandbox Code Playgroud)

上面将给出 13 到 125 (113-1+13) 之间的数字,具有合理的随机熵。

  • 我添加了一个调整来消除前导零: RANDOM=$(date +%s%N | cut -b10-19 | sed -e 's/^0*//;s/^$/0/') (2认同)
  • @Roel你是对的,我错过了一点,我们必须分配给“RANDOM”而不带前导零来播种随机数生成器。不过,使用另一个变量也是一种选择:[实例](https://onlinegdb.com/B1JJRkauv); 一条额外的线路,但不是额外的过程。感谢您的回答和链接:) (2认同)

Jan*_*usz 6

如果您使用的是Linux系统,则可以从/ dev/random或/dev/urandom中获取随机数.如果没有足够的随机数,请小心/ dev/random将阻止.如果你需要速度超过随机性使用/ dev/urandom.

这些"文件"将填充操作系统生成的随机数.如果你得到真或伪随机数,它取决于你的系统上/ dev/random的实现.使用从鼠标,硬盘驱动器,网络等设备驱动程序收集的噪音帮助生成真随机数.

您可以使用dd从文件中获取随机数


Vin*_*cco 6

也许我有点太晚了,但是jot在 Bash 中使用在一定范围内生成随机数怎么样?

jot -r -p 3 1 0 1
Run Code Online (Sandbox Code Playgroud)

这将生成一个-r具有 3 位小数精度 ( ) 的随机数 ( -p)。在这种特殊情况下,您将得到 0 到 1 之间的一个数字 ( 1 0 1)。您还可以打印连续数据。根据手册,随机数的来源是:

当未指定种子时,通过 arc4random(3) 获得随机数;当给定种子时,通过 random(3) 获得随机数。

  • 必须安装: sudo apt install athena-jot (3认同)

Cod*_*ine 6

没有取模的纯 Bash 随机数

lowerRange=10   # inclusive
upperRange=20   # exclusive

randomNumber=$(( RANDOM * ( upperRange - lowerRange) / 32767 + lowerRange ))
Run Code Online (Sandbox Code Playgroud)


phi*_*urn 5

我采纳了其中的一些想法,并制作了一个函数,如果需要大量随机数,该函数应该可以快速执行。

od如果您需要大量随机数,则通话费用很高。相反,我只调用它一次,并从/ dev / urandom中存储1024个随机数。当rand被调用时,最后一个随机数返回和缩放。然后将其从缓存中删除。当缓存为空时,将读取另一个1024个随机数。

例:

rand 10; echo $RET
Run Code Online (Sandbox Code Playgroud)

在RET中返回一个介于0和9之间(含0和9)的随机数。

declare -ia RANDCACHE
declare -i RET RAWRAND=$(( (1<<32)-1 ))

function rand(){  # pick a random number from 0 to N-1. Max N is 2^32
  local -i N=$1
  [[ ${#RANDCACHE[*]} -eq 0 ]] && { RANDCACHE=( $(od -An -tu4 -N1024 /dev/urandom) ); }  # refill cache
  RET=$(( (RANDCACHE[-1]*N+1)/RAWRAND ))  # pull last random number and scale
  unset RANDCACHE[${#RANDCACHE[*]}-1]     # pop read random number
};

# test by generating a lot of random numbers, then effectively place them in bins and count how many are in each bin.

declare -i c; declare -ia BIN

for (( c=0; c<100000; c++ )); do
  rand 10
  BIN[RET]+=1  # add to bin to check distribution
done

for (( c=0; c<10; c++ )); do
  printf "%d %d\n" $c ${BIN[c]} 
done
Run Code Online (Sandbox Code Playgroud)

更新:并不是所有N都很好。如果与小N一起使用,也会浪费随机位。请注意(在这种情况下)32位随机数具有足够的熵,可以容纳0到9之间的9个随机数(10 * 9 = 1,000,000,000 <= 2 * 32)我们可以从每个32个随机源值中提取多个随机数。

#!/bin/bash

declare -ia RCACHE

declare -i RET             # return value
declare -i ENT=2           # keep track of unused entropy as 2^(entropy)
declare -i RND=RANDOM%ENT  # a store for unused entropy - start with 1 bit

declare -i BYTES=4         # size of unsigned random bytes returned by od
declare -i BITS=8*BYTES    # size of random data returned by od in bits
declare -i CACHE=16        # number of random numbers to cache
declare -i MAX=2**BITS     # quantum of entropy per cached random number
declare -i c

function rand(){  # pick a random number from 0 to 2^BITS-1
  [[ ${#RCACHE[*]} -eq 0 ]] && { RCACHE=( $(od -An -tu$BYTES -N$CACHE /dev/urandom) ); }  # refill cache - could use /dev/random if CACHE is small
  RET=${RCACHE[-1]}              # pull last random number and scale
  unset RCACHE[${#RCACHE[*]}-1]  # pop read random number
};

function randBetween(){
  local -i N=$1
  [[ ENT -lt N ]] && {  # not enough entropy to supply ln(N)/ln(2) bits
    rand; RND=RET       # get more random bits
    ENT=MAX             # reset entropy
  }
  RET=RND%N  # random number to return
  RND=RND/N  # remaining randomness
  ENT=ENT/N  # remaining entropy
};

declare -ia BIN

for (( c=0; c<100000; c++ )); do
  randBetween 10
  BIN[RET]+=1
done

for c in ${BIN[*]}; do
  echo $c
done
Run Code Online (Sandbox Code Playgroud)


k-h*_*k-h 5

关于什么:

perl -e 'print int rand 10, "\n"; '
Run Code Online (Sandbox Code Playgroud)

  • 对于加密安全的随机数,您需要从 /dev/urandom 读取或使用 Crypt::Random 库。 (2认同)

4pi*_*ie0 5

从/ dev / random或/ dev / urandom字符特殊文件读取是一种方法。

这些设备在读取时会返回真正的随机数,旨在帮助应用程序软件选择安全密钥进行加密。从由各种随机事件贡献的熵池中提取这样的随机数。{LDD3,Jonathan Corbet,Alessandro Rubini和Greg Kroah-Hartman]

这两个文件是内核随机化的接口,特别是

void get_random_bytes_arch(void* buf, int nbytes)
Run Code Online (Sandbox Code Playgroud)

如果此功能是由硬件实现的(通常是),则从硬件中抽取真正随机的字节,或者从熵池(由事件之间的定时组成,例如鼠标和键盘中断以及在SA_SAMPLE_RANDOM中注册的其他中断之间的定时)提取。

dd if=/dev/urandom count=4 bs=1 | od -t d
Run Code Online (Sandbox Code Playgroud)

这可行,但是将不需要的输出从写入ddstdout。下面的命令仅给出我需要的整数。通过调整算术扩展的位掩码,我什至可以根据需要获得指定数量的随机位:

me@mymachine:~/$ x=$(head -c 1 /dev/urandom > tmp && hexdump 
                         -d tmp | head -n 1 | cut -c13-15) && echo $(( 10#$x & 127 ))
Run Code Online (Sandbox Code Playgroud)