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


当前回答

生成随机的3位数字

这对于创建示例数据非常有用。示例:将所有测试数据放在名为“test-create-volume-123”的目录中,然后在测试完成后,删除整个目录。通过生成恰好三个数字,就不会有奇怪的排序问题。

printf '%02d\n' $((1 + RANDOM % 100))

这是按比例缩小的,例如到一个数字:

printf '%01d\n' $((1 + RANDOM % 10))

它可以放大,但只能放大到四位数。原因见上文:)

其他回答

请参阅$RANDOM:

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

我已经采取了一些这些想法,并做出了一个函数,应该执行迅速,如果大量的随机数是必需的。

如果你需要很多随机数,调用od的代价是很高的。相反,我只调用它一次,并存储来自/dev/urandom的1024个随机数。当调用rand时,返回最后一个随机数并按比例缩放。然后从缓存中删除它。当缓存为空时,再读取1024个随机数。

例子:

rand 10; echo $RET

返回RET中0到9(含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

更新:这并不适用于所有n。如果使用小n,也会浪费随机比特。注意(在这种情况下)一个32位随机数有足够的熵容纳9个0到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

我就此写了几篇文章。

https://linuxconfig.org/generating-random-numbers-in-bash-with-examples https://linuxconfig.org/random-entropy-in-bash https://www.cloudsavvyit.com/7572/how-to-generate-better-random-numbers-at-the-bash-command-line/

$ RANDOM=$(date +%s%N | cut -b10-19)
$ echo $(( $RANDOM % 113 + 13 ))

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

还可以使用shuf(可在coreutils中使用)。

shuf -i 1-100000 -n 1

使用随机的美元。它通常与简单的shell算法结合使用很有用。例如,要生成1到10(包括)之间的随机数:

$ echo $((1 + $RANDOM % 10))
3

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

如果你在做一些需要大量随机数的事情,你可以使用/dev/random或/dev/urandom(如果它们可用的话):

$ dd if=/dev/urandom count=4 bs=1 | od -t d