如何在Bash中生成随机数?


Answers:


283

使用$RANDOM。与简单的Shell算术结合使用时通常很有用。例如,要生成1到10(含)之间的随机数:

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

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

如果您要执行的操作需要严重的随机数,则可以使用/dev/random/dev/urandom可用:

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

20
小心点 虽然这很好,但对随机数进行算术运算会极大地影响结果的随机性。在的情况下$RANDOM % 10,即使$RANDOM是可靠的随机数据源,8和9的概率(尽管在边际上)也比0-7小得多。
dimo414

3
@ dimo414我很好奇“微不足道”,您是否有资料来源可以在此找到更多信息?
PascalVKooten

58
通过moduloing你随意输入,你是“ 对号入座 ”的结果。由于$RANDOM的范围是0-327670- 7映射到3277不同的可能输入,但89只能产生3276不同的方式(因为3276832769是不可能的)。对于快速黑客来说,这是一个小问题,但是这意味着结果并非一律随机。像Java一样Random,随机库提供的功能可正确返回给定范围内的统一随机数,而不是简单地修改不可除数。
dimo414

1
@JFSebastian非常正确-模的问题是它会破坏任何 RNG 的一致性,不仅是不良的PRNG,而且还要感谢您提出来。
dimo414 2014年

14
仅就上下文而言,%10的基本归类意味着8和9比0–7发生的可能性要低约0.03%。如果您的shell脚本需要比这更准确的统一随机数,那么请务必使用更复杂和适当的机制。
尼尔森

70

请参阅$RANDOM

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


1
是否32767有什么特殊的意义?
Jin Kwon

14
@JinKwon 327672^16 / 2 - 1有符号的16位整数的上限。
杰弗里·马丁内斯

@JinKwon您能否澄清为什么不这样说2^15 - 1?这是等效的,所以我很好奇是否缺少某些上下文?
布雷特·霍尔曼

11
@BrettHolman我认为他试图指出有符号16位整数的“有符号”部分。2 ^ 16个值,对于正整数和负整数均分为两半。
科迪

该答案不能回答问题。
小子

48

您也可以使用shuf(在coreutils中可用)。

shuf -i 1-100000 -n 1

范围结束时如何传递var?我得到了:shuf -i 1-10 -n 1: syntax error in expression (error token is "1-10 -n 1")
dat tutbrus

1
添加一个$var而不是范围末尾,例如:var=100 && shuf -i 1-${var} -n 1
knipwim18年

2
我更喜欢这个选项,因为使用可以很容易地生成N个随机数-n。例如,生成1至100之间的5个随机数shuf -i 1-100 -n 5
aerijman

据我了解,数字不是随机的。如果指定shuf -i 1-10 -n 10,则将得到从1到10的所有数字,精确到一个。如果您指定,-n 15您仍然只会准确地获得那10个数字。这实际上只是改组,不会生成随机数。
radlan

要获取具有替换的随机数:-r
Geoffrey Anderson

36

在您的shell中尝试一下:

$ od -A n -t d -N 1 /dev/urandom

在这里,-t d指定输出格式应为十进制符号;-N 1表示要从中读取一个字节/dev/urandom


2
问题要求输入一个范围内的数字。
JSycamore

9
您可以删除空格:od -A n -t d -N 1 /dev/urandom |tr -d ' '
罗伯特

23

你也可以从awk获得随机数

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

1
+1,你知道,起初我虽然为什么会想这样做,但实际上我还是很喜欢。
zelanix 2014年

1
感谢您提供包含播种的解决方案。我在任何地方都找不到!
so.very.tired

2
+1进行播种。可能值得一提的是srand(),的种子是当前的CPU时间。如果需要指定特定的种子,以便可以复制RNG,请使用srand(x)where x是种子。同样,引自GNU awk的数字功能手册,“不同的awk实现内部使用了不同的随机数生成器。” 结果是,如果您对生成统计信息分布感兴趣,则应该期望从一个运行时到另一个运行在不同平台(所有运行awkgawk)上的轻微变化。
Cbhihe


17

我喜欢这个技巧:

echo ${RANDOM:0:1} # random number between 1 and 9
echo ${RANDOM:0:2} # random number between 1 and 99

...


6
$ RANDOM的范围是0-32767。与4-9相比,最终以1、2或3开头的数字更多。如果您可以接受分配不平衡的情况,则可以正常使用。
jbo5112 '18

2
@ jbo5112您完全正确,那么显示最后一位呢?回显$ {RANDOM:0-1}表示一位,$ {RANDOM:0-2}表示两位... ...
fraff

3
如果使用最后一位数字,那会比较好,但是它将包含0和00。在一个数字上,0-7的发生频率比8-9的发生频率高0.03%。在2位数字上,0-67的发生频率比68-99的发生频率高0.3%。如果您需要一个很好的随机数分布,则希望您不使用bash。原件:${RANDOM:0:1}给您1或2的几率达67.8%,给您一个${RANDOM:0:2}数字(应为1%)的几率只有0.03%,给您0的几率都为0.003% 。在某些情况下,这仍然很好(例如,输入不一致)。
jbo5112 '18

12

介于0和9之间(含0和9)的随机数。

echo $((RANDOM%10))

2
我不好,没有正确阅读手册页。$RANDOM只能从0到32767。它应该说“随机数通常在1到3之间,并且有一些边锋”;)
David Newcomb 2013年

1
什么?仍然在0到9之间,尽管8和9的出现几率要比0到7稍低,如另一个答案中所述。
kini

6

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

这些“文件”将填充由操作系统生成的随机数。如果获得真或伪随机数,则取决于系统上/ dev / random的实现。真正的随机数是借助从鼠标,硬盘驱动器,网络等设备驱动程序收集到的噪声形式生成的。

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


5

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

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

例:

rand 10; echo $RET

在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

更新:并不是所有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

我尝试了这一点-花了10秒的100%cpu,然后打印了10个看起来并非随机的数字。
卡罗·伍德

我现在想起了。此代码生成100,000个随机数。它将每个放入“ bin”中以查看其随机性。有10个垃圾箱。如果介于0到9之间的每个随机数同等可能,则这些数字应相似。如果要打印每个数字,请在randBetween 10之后回显$ RET。–
philcolbourn

od -An -tu4 -N40 /dev/urandom将生成10个随机的无符号32位整数,用空格分隔。您可以将其存储在数组中,然后使用。您的代码似乎太过分了。
阿里

@ Ali,OP没有指定他们想要32位或任何其他大小的随机数。我和其他一些人将此问题解释为在一定范围内提供随机数。我的rand函数实现了这一目标,并且还减少了熵损失(如果耗尽了,该熵会导致程序阻塞)。/ dev / urandom上的od仅返回2 ^ N位随机数,然后OP需要将多个值存储到一个数组中,从该数组中顺序提取它们,并补充该数组。也许您可以将此编码为答案并处理其他随机数范围?
philcolbourn 2015年

@philcolbourn,关于OP没有指定他想要哪种随机数,您是正确的,并且错过了我的注意力。但是他只问:“如何在bash中生成一个随机数?”。我的意思是,他只要求一个随机数。尽管此评论家也适用于我之前的评论(生成10个随机数)。
阿里

5

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

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

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

void get_random_bytes_arch(void* buf, int nbytes)

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

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

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

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

3

关于什么:

perl -e 'print int rand 10, "\n"; '

对于加密安全的随机数,您需要从/ dev / urandom中读取或使用Crypt :: Random库。
kh

3

也许我为时已晚,但是使用jotBash在范围内生成随机数又如何呢?

jot -r -p 3 1 0 1

这将生成一个随机(-r)数字,精度为3个小数位-p。在这种情况下,您会得到一个介于0和1(1 0 1)之间的数字。您也可以打印顺序数据。根据手册,随机数的来源是:

如果未指定种子,则通过arc4random(3)获得随机数;如果给出种子,则通过random(3)获得随机数。


必须安装:sudo apt install athena-jot
xerostomus

3

基于@ Nelson,@ Barun和@Robert的出色答案,这是一个生成随机数的Bash脚本。

  • 可以生成您想要的位数。
  • 每个数字都是单独生成的/dev/urandom,比Bash的内置数字好得多$RANDOM
#!/usr/bin/env bash

digits=10

rand=$(od -A n -t d -N 2 /dev/urandom |tr -d ' ')
num=$((rand % 10))
while [ ${#num} -lt $digits ]; do
  rand=$(od -A n -t d -N 1 /dev/urandom |tr -d ' ')
  num="${num}$((rand % 10))"
done
echo $num

正是我所追求的。
普罗米修斯

2

生成0到n范围内的随机数(带符号的16位整数)。结果设置在$ RAND变量中。例如:

#!/bin/bash

random()
{
    local range=${1:-1}

    RAND=`od -t uI -N 4 /dev/urandom | awk '{print $2}'`
    let "RAND=$RAND%($range+1)"
}

n=10
while [ $(( n -=1 )) -ge "0" ]; do
    random 500
    echo "$RAND"
done

1

程序的随机分支或是/否;1/0; 正确/错误输出:

if [ $RANDOM -gt 16383  ]; then              # 16383 = 32767/2 
    echo var=true/1/yes/go_hither
else 
    echo var=false/0/no/go_thither
fi

如果您不愿记住16383:

if (( RANDOM % 2 )); then 
    echo "yes"
else 
    echo "no"
fi
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.