my_rnd=$(((RANDOM<<15|RANDOM)))
What this does is only to use RANDOM
twice, for 15 bits each, with the first value moved by 15 bits to the left. So you get a binary number like aaaaaaaaaaaaaaabbbbbbbbbbbbbbb
, where the a's are bits representing the first value and the b's the ones representing the second.
Similarly, to get any number of bits, you could use either RANDOM
or SRANDOM
to generate at least that many bits, collected together with shift (<<
) and or (|
), and then mask the rest out with and (&
). E.g. for 32 bits, you'd use a mask of 0xffffffff
:
echo "$(( ((RANDOM<<30) | (RANDOM<<15) | RANDOM) & 0xffffffff ))"
(0xffffffff
is the maximum 32-bit binary value, 4294967295 in decimal. You could also use ((1 << 32) - 1)
to calculate it on the fly.)
Note that Bash's manual doesn't seem to make any promises about how non-predictable the values produced by RANDOM
are, but for SRANDOM
it says that:
SRANDOM
This variable expands to a 32-bit pseudo-random number each time it is referenced. The random number generator is not linear on systems that support /dev/urandom
or arc4random
, so each returned number has no relationship to the numbers preceding it.
which implies that RANDOM
could indeed be a linear congruential generator, which is to say, not a very good random generator. /dev/urandom
and arc4random
are implemented with better algorithms, so if it's available, you should use SRANDOM
.
Even if SRANDOM
is not available in your version of Bash, chances are your system has /dev/urandom
available. So, if you do need better random numbers than what RANDOM
provides, you could use that directly. Building on an answer in Using /dev/random, /dev/urandom to generate random data, this would fill the shell array arr
with n
random 32-bit numbers:
n=10
arr=( $(od -vAn -N $((n*4)) -tu4 < /dev/urandom) )
(using word splitting on purpose, IFS
must not contain digits.)
signed long
, so you might get a signed 32-bit integer here and therefore a negative value. Calling Ruby'sSecureRandom.rand
would be a better option.