Unix Shell - 为什么重复相同的 $RANDOM 数字?

Unix Shell - Why are the same $RANDOM numbers repeated?

我在 Unix shell 中试验 $RANDOM 变量并注意到一些奇怪的东西。我 运行 下面的命令,它在循环中读取 $RANDOM 100k 次,然后将输出通过管道传输到“uniq”以查找重复项。

$ for i in {1..100000}; do echo $RANDOM; done | uniq -d

我运行上面的命令7次,同样的两个数字(4455和4117)重复了7次。下面的屏幕截图显示了命令行输出。

kali@kali:~% for i in {1..100000}; do echo $RANDOM; done | uniq -d
4455
4117
kali@kali:~% for i in {1..100000}; do echo $RANDOM; done | uniq -d
4455
4117
kali@kali:~% for i in {1..100000}; do echo $RANDOM; done | uniq -d
4455
4117
kali@kali:~% for i in {1..100000}; do echo $RANDOM; done | uniq -d
4455
4117
kali@kali:~% for i in {1..100000}; do echo $RANDOM; done | uniq -d
4455
4117
kali@kali:~% for i in {1..100000}; do echo $RANDOM; done | uniq -d
4455
4117
kali@kali:~% for i in {1..100000}; do echo $RANDOM; done | uniq -d
4455
4117

参见:https://i.stack.imgur.com/5bpEe.png

我还打开了另一个终端window并重复了这个过程。在第二个终端中,数字不同,但以类似的方式重复。这让我想知道什么时候 $RANDOM 变量的熵,以及它是如何播种的。

我的猜测是每当调用 bash 时它都会重新播种,但我想知道是否有人知道为什么当我在单个终端中重复命令时重复相同的值 window.

随机数生成器并不完美。具有“标准”常量的 Lehmer random number generator is used in bash sources

x(n+1) = 16807 * x(n) mod (2**31 - 1)

而且bash限制了output to 15 bits only:

#  define BASH_RAND_MAX 32767
...
return ((unsigned int)(rseed & BASH_RAND_MAX));

随着你的shell种子被播种,恰好在连续输出10000个随机数中,数字44554117相继出现。真的没什么好惊讶的。您可以计算种子以获得两个连续的数字:

# We know that lower 15 bits of previous number are equal to 4455
x(n) mod 32768 = 4455
# We know that lower 15 bits of previous number are equal to 4455
x(n+1) mod 32768 = 4455
# We know the relation between next and previous number
x(n+1) = 16807 * x(n) mod (2**31 - 1)
# You could find x(n)

Why are the same $RANDOM numbers repeated?

因为 bash 来源中使用的伪随机生成器方法与您 shell 中的当前种子恰好重复相同的数字。

这是由于子 shell 中 RANDOM 的 zsh 错误/“行为”。此错误未出现在 bash.

echo $RANDOM # changes at every run  
echo `echo $RANDOM` # always return the same value until you call the first line

因为 RANDOM 是由它的最后一个值播种的,但是在子 shell 中获得的值不会在主 shell.

中更新

man zshparam中:

RANDOM <S>
A  pseudo-random  integer  from 0 to 32767, newly generated each
time this parameter is referenced.  The random number  generator
can be seeded by assigning a numeric value to RANDOM.

The   values   of   RANDOM   form   an  intentionally-repeatable
pseudo-random sequence; subshells  that  reference  RANDOM  will
result  in  identical  pseudo-random  values unless the value of
RANDOM is referenced or seeded in the parent  shell  in  between
subshell invocations.

还有更疯狂的,因为调用 uniq 会创建一个子shell

for i in {1..10}; do echo $RANDOM; done # changes at every run 
for i in {1..10}; do echo $RANDOM; done | uniq # always the same 10 numbers

来源:Debian bug report 828180