我正在尝试使用bash终端中的$ RANDOM函数在指定范围之间生成一个随机数。问题是它产生的数字似乎根本不是随机的。我使用的脚本是:
RANDOM=$$;
a=$RANDOM
b=9; #Number of scripts in collection -1
c=`expr $a % $b `; #Random number between 0 and b
if (( c==0 ));
then
echo "script 1 (random = $a, mod = $c)";
elif (( c==1 ));
then
echo "stript 2 (random = $a, mod = $c)";
...
else
echo "error (random = $a, mod = $c)";
fi;
如果我在for循环中运行它,我会得到,例如:
script 8 (random = 17845, mod = 7)
script 8 (random = 18754, mod = 7)
script 8 (random = 19663, mod = 7)
script 7 (random = 20571, mod = 6)
script 7 (random = 21480, mod = 6)
script 6 (random = 22388, mod = 5)
script 6 (random = 23297, mod = 5)
script 6 (random = 24206, mod = 5)
script 5 (random = 25114, mod = 4)
script 5 (random = 26023, mod = 4)
这显然不是随机的。
我尝试删除$ a并运行
c=`expr $RANDOM % $b`;
然后将代码更改为另一个变体
c=`expr $a \* $b \/ 32767`;
但这些(不出所料)返回了相同的结果。我究竟做错了什么?或者这对$ RANDOM来说只是一个有点刺激性的限制?任何建议都将不胜感激。
答案 0 :(得分:2)
你一直用相同的号码播种RANDOM。尽量不要播种或使用更随机的项目播种:
RANDOM=$$
显然$$
不会一直改变,因为它始终是shell的主PID(不是子shell PID)。如果你实际上正在调用不同的shell,那么可能没有太大区别,因为每个PID增加的数字仅增加1。所以要么你可以删除它,要么在/dev/urandom
等地方获得另一个随机种子
通过/dev/urandom
应用随机种子的一种好方法:
RANDOM=$(tr -dc 0-9 < /dev/urandom | head -c10)
另一个纳秒(播种数量大于这些似乎没有产生良好效果):
RANDOM=$(date '+%N')
另外,为了使它在不同的子流程中看起来更独特,请将BASHPID(优于$$)添加到种子中:
RANDOM=$(( BASHPID + $(date '+%N') ))
答案 1 :(得分:2)
我认为可以找到解释here:
当您使用模数运算时,您正在从中选择信息 一个数字的低位和从中丢弃的信息 高阶位... X的最低有效(右手)数字 不是很随机,所以基于数字X的决定应该始终如此 主要受最重要数字的影响。
使用这个 对我来说效果更好(虽然我只测了几次):
c=$(($a * $b / 32768))
这是经过修改的脚本:
#!/bin/bash
RANDOM=$$;
a=$RANDOM
b=9; #Number of scripts in collection -1
c=$(($a * $b / 32768))
if (( c==0 )); then
echo "script 1 (random = $a, mod = $c)";
elif (( c==1 )); then
echo "script 2 (random = $a, mod = $c)";
else
echo "error (random = $a, mod = $c)";
fi;
希望这有帮助。