2

Environment:

  • Debian
  • Bash

What is known:

RANDOM gives a random number in a range of 15 bits by the following:

echo $RANDOM

SRANDOM gives a random number in a range of 32 bits by the following:

echo $SRANDOM

RANDOM can be configured to create random numbers in a 30-bit range by the following:

my_rnd=$(((RANDOM<<15|RANDOM)))
echo "$my_rnd"

RANDOM can be configured to create random numbers in a 45-bit range by the following:

my_rnd=$(((RANDOM<<15|RANDOM)<<15|RANDOM))
echo "$my_rnd"

How can I configure RANDOM to get the same 32-bit range of random numbers as I get when using SRANDOM?

1
  • In general, if you need anything other than the simplest random numbers, bash is not a good language to write this. Moreover, POSIX only guarantees arithmetic in signed long, so you might get a signed 32-bit integer here and therefore a negative value. Calling Ruby's SecureRandom.rand would be a better option.
    – bk2204
    Commented Jul 21, 2021 at 22:30

2 Answers 2

6
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.)

2
  • 2
    In older versions of bash, $RANDOM (initially a ksh feature) randomness was notoriously very bad and hardly usable. Commented Jul 21, 2021 at 19:37
  • Previously the random function was located in variables.c, made according to Park and Miller (1988). Bash 5.1 introduced SRANDOM (cryptographic-grade /dev or arc4, LC fallback) and got a new RNG for RANDOM (same one, but better folding to 16-bit); code for both is in lib/sh/random.c. Commented Aug 15 at 3:36
5

You could just do:

(( my_rnd = (RANDOM << 17) | (RANDOM << 2) | (RANDOM & 3) ))

That is, take all 15 bits of a first RANDOM, shifted 17 bits, another 15 bits of another RANDOM, shifted 2 bits, and an extra 2 bits of a third RANDOM (the lower ones, you could also use RANDOM >> 13 for the higher ones, which at least in older versions of bash were significantly more random).

4
  • Its sounds for me the quality of RANDOM on new and old systems can be verry differnt. Which solution can be a good choice for unknown systems, which can be verry or old r actual also ?
    – Alfred.37
    Commented Jul 21, 2021 at 22:18
  • 1
    @Eddy763, the poor randomness in the low bits is something I remember from the 90s. I don't know exactly when it was fixed but it probably was over 10 years ago so you're probably fine nowadays. In any case, whilst (pseudo-)random, $RANDOM is not cryptographically safe in that it is predictable. So not OK to generate passwords for instance. Commented Jul 22, 2021 at 6:18
  • 1
    @Eddy763 The Wikipedia page on LCGs has a couple of notes about the weaknesses in the low bits, but they depend on the magic numbers of the LCG. Bash looks to use x * 16807 mod 2^31-1, and uses a 32-bit value but returns only 15 bits, so it doesn't have the most critical issues. (Which would come if the modulus was a power of two.) It looks like the same equation since 4.0. But no, not in the same ballpark as actual cryptographically strong RNGs.
    – ilkkachu
    Commented Jul 29, 2021 at 11:19
  • @Stéphane Chazelas Can you add the solution for the follow "you could also use RANDOM >> 13" THX
    – Alfred.37
    Commented Apr 7, 2023 at 14:10

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .