生成特定范围内的随机数


84

谷歌搜索了一下之后,我找不到一种简单的方法来使用shell命令来生成一个包含在特定范围内的随机十进制整数,该范围介于最小值和最大值之间。

我了解/dev/random/dev/urandom$RANDOM,但这些都不可以做什么,我需要。

还有其他有用的命令,还是使用先前数据的方法?




Answers:


45

在POSIX工具箱中,您可以使用awk

awk -v min=5 -v max=10 'BEGIN{srand(); print int(min+rand()*(max-min+1))}'

千万不能使用它作为源生成口令或例如秘密数据,与大多数awk实现中,数量可以很容易地根据该命令运行的时间猜测。

对于许多awk实现,该命令在同一秒内运行两次通常会为您提供相同的输出。


1
+1 ..在脚本中用于将输出分配给变量(不引入换行符并在两个位置使用零填充):x=$(awk -v min=$min_var -v max=$max_var 'BEGIN{srand(); printf("%.2d", int(min+rand()*(max-min+1)))}')
Christopher,

它是基于时间的?因为我连续2次获得相同的价值...
Shai Alon

@ShaiAlon当前时间通常用作srand()的默认种子值,因此通常,是的,它基于时间,请参见他的答案中Stéphane的句子。您可以通过使用将初始种子更改为随机数来解决此问题awk -v min=5 -v max=10 -v seed="$(od -An -N4 -tu4 /dev/urandom)" 'BEGIN{srand(seed+0); print int(min+rand()*(max-min+1))}'。您可以使用$RANDOM代替,od ... /dev/random但是您的种子值在0到32767的相对较小范围内,因此随着时间的推移,您的输出中可能会出现明显的重复。
Ed Morton

141

您可以shuf从GNU coreutils 尝试:

shuf -i 1-100 -n 1

这也适用于Busybox shuf
cov

也可以在raspbian和GitBash中使用。
nPcomp

30

记号

在BSD和OSX上,您可以使用jot返回-r从时间间隔min到的单个随机()数字(max含)。

$ min=5
$ max=10
$ jot -r 1 $min $max

发行问题

不幸的是,随机生成的数字的范围和分布受以下事实的影响:jot在内部使用双精度浮点算术并对输出格式使用printf(3),这会导致舍入和截断问题。因此,间隔minmax的生成频率较低,如下所示:

$ jot -r 100000 5 10 | sort -n | uniq -c
9918  5
20176 6
20006 7
20083 8
19879 9
9938  10

在OS X 10.11(El Capitan)上,此问题似乎已解决:

$ jot -r 100000 5 10 | sort -n | uniq -c
16692 5
16550 6
16856 7
16579 8
16714 9
16609 10  

和...

$ jot -r 1000000 1 10 | sort -n | uniq -c
100430 1
99965 2
99982 3
99796 4
100444 5
99853 6
99835 7
100397 8
99588 9
99710 10

解决分配问题

对于旧版本的OS X,幸运的是,有几种解决方法。一种是使用printf(3)整数转换。唯一的警告是最大间隔现在变为max+1。通过使用整数格式,我们可以在整个时间间隔内公平分配:

$ jot -w %i -r 100000 5 11 | sort -n | uniq -c
16756 5
16571 6
16744 7
16605 8
16683 9
16641 10

完美的解决方案

最后,为了使用解决方法公平地掷骰子,我们有:

$ min=5
$ max_plus1=11  # 10 + 1
$ jot -w %i -r 1 $min $max_plus1

额外的作业

参见jot(1)以获得更多的数学知识和格式细节,以及更多示例。


15

$RANDOM变量通常不会产生良好的随机值的好方法。/dev/[u]random需要的输出也必须先转换。

一种更简单的方法是使用高级语言,例如python:

要生成介于5和10之间的随机整数变量(5 <= N <= 10),请使用

python -c "import random; print random.randint(5,10)"

不要将此用于加密应用程序。


这很有用。非常感谢:)就像在Unix-> Solaris 10上经常使用签名一样,默认情况下不集成GNU utils。但是,这有效。
宣传

11

您可以通过获得随机数 urandom

head -200 /dev/urandom | cksum

输出:

3310670062 52870

要检索上述编号的一部分。

head -200 /dev/urandom | cksum | cut -f1 -d " "

然后输出是

3310670062


head -200(或者其等效POSIX head -n 100)返回前200 /dev/urandom/dev/urandom不是文本文件,该命令可以从200个字节(全为0x0a,ASCII中为LF)返回到无穷大(如果从不返回0xa字节),但最有可能介于45k和55k之间。cksum返回一个32位数字,因此从中获取4个以上的字节毫无意义/dev/urandom
斯特凡·查泽拉斯

7

要生成介于5到10(包括两者)之间的随机整数变量,请使用

echo $(( RANDOM % (10 - 5 + 1 ) + 5 ))

% 作为模运算符。

将随机变量$RANDOM转换为特定范围可能有更好的方法。请勿将其用于加密应用程序,或者在您需要真实,均匀分布的随机变量(例如用于模拟)的情况下。


3
在许多确实具有$ RANDOM的shell实现中(尤其是较旧的,尤其是bash),这不是很随机。在大多数shell中,该数字在0到65535之间,因此宽度不为2的幂的任何范围将具有概率分布差异。(在这种情况下,数字5至8的概率为10923/65536,而数字9和10的概率为10922/65536)。范围越宽,差异越大。
斯特凡Chazelas

抱歉,这是32767,而不是65535,因此上面的计算是错误的(实际上更糟)。
斯特凡Chazelas

@StéphaneChazelas当我写到有更好的方法时,我想到了这一点
jofel 2014年


4

也许UUID(在Linux上)可用于检索随机数

$ cat /proc/sys/kernel/random/uuid
cdd52826-327d-4355-9737-895f58ad11b4

获取介于70和之间的随机数100

POSIXLY_CORRECT=1 awk -F - '{print(("0x"$1) % 30 + 70)}
   ' /proc/sys/kernel/random/uuid

3
cat /dev/urandom | tr -dc 'a-fA-F0-9' | fold -w 8 | head -n 1

这将生成一个8位长的十六进制数字。


1

要完全停留在bash中并使用$ RANDOM变量,但要避免分布不均:

#!/bin/bash
range=10 
floor=20

if [ $range -gt 32768 ]; then
echo 'range outside of what $RANDOM can provide.' >&2
exit 1 # exit before entering infinite loop
fi 

max_RANDOM=$(( 2**15/$range*$range ))
r=$RANDOM
until [ $r -lt $max_RANDOM ]; do
r=$RANDOM
done
echo $(( r % $range + $floor ))

本示例将提供20到29之间的随机数。


$r应将其初始化为65535或其他较高的值,以免发生[: -lt: unary operator expected错误。
LawrenceC

在循环测试之前,已更正$ r初始化。谢谢@LawrenceC!
比Angell

0

分布良好:

对于((i = 1; i <= 100000; i ++))做echo $((RANDOM%(20-10 + 1)+ 10)); 完成| 排序-n | uniq -c

计数值

9183 10

9109 11

8915 12

9037 13

9100 14

9138 15

9125 16

9261 17

9088 18

8996 19

9048 20

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.