Unix $RANDOM function not random in Bash terminal

て烟熏妆下的殇ゞ 提交于 2019-12-11 11:00:52

问题


I'm trying to generate a random number in between a specified range by using the $RANDOM function in the bash terminal. The problem is that the numbers it is generating don't appear to be random at all. The script I am using is:

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;

If I run this in a for in loop I get, for example:

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)

Which clearly isn't random.

I tried removing the $a and just running

c=`expr $RANDOM % $b`; 

and then altering the code to another variation

c=`expr $a \* $b \/ 32767`;

But these (unsurprisingly) returned the same result. What am I doing wrong? Or is this just a slightly irritating limitation for $RANDOM? Any advice would be greatly appreciated.


回答1:


You kept seeding RANDOM with the same number. Try not to seed it or seed it with a more random item instead:

RANDOM=$$

Apparently $$ doesn't change always as it's always the main PID (not subshell PID) of your shell. If you're actually calling different shells, probably there isn't much difference since the numbers seeded by every PID increments only by ones. So either you could remove that or get another random seed somewhere like /dev/urandom, etc.

One good way to apply a random seed by /dev/urandom:

RANDOM=$(tr -dc 0-9 < /dev/urandom | head -c10)

Another through nanoseconds (seeding larger numbers than these seems to not give a good effect):

RANDOM=$(date '+%N')

Also to make it look more unique among different subprocesses, add BASHPID (better than $$) to your seed:

RANDOM=$(( BASHPID + $(date '+%N') ))



回答2:


I think the explanation is to be found here:

When you use a modulus operation you are selecting information from the low order bits of a number and discarding information from the high order bits... The least significant (right-hand) digits of X are not very random, so decisions based on the number X should always be influenced primarily by the most significant digits.

And using this does work better for me (though I only tested a few times):

c=$(($a * $b / 32768))

Here's the revised script:

#!/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;

Hope this helps.



来源:https://stackoverflow.com/questions/18678675/unix-random-function-not-random-in-bash-terminal

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!