[bash] How to generate random number in Bash?

How to generate a random number within a range in Bash?

This question is related to bash shell random

The answer is


Generate random 3-digit number

This is great for creating sample data. Example: put all testing data in a directory called "test-create-volume-123", then after your test is done, zap the entire directory. By generating exactly three digits, you don't have weird sorting issues.

printf '%02d\n' $((1 + RANDOM % 100))

This scales down, e.g. to one digit:

printf '%01d\n' $((1 + RANDOM % 10))

It scales up, but only to four digits. See above as to why :)


Random branching of a program or yes/no; 1/0; true/false output:

if [ $RANDOM -gt 16383  ]; then              # 16383 = 32767/2 
    echo var=true/1/yes/go_hither
else 
    echo var=false/0/no/go_thither
fi

of if you lazy to remember 16383:

if (( RANDOM % 2 )); then 
    echo "yes"
else 
    echo "no"
fi

Random number between 0 and 9 inclusive.

echo $((RANDOM%10))

I wrote several articles on this.

$ RANDOM=$(date +%s%N | cut -b10-19)
$ echo $(( $RANDOM % 113 + 13 ))

The above will give a number between 13 and 113, with reasonable random entropy.


Generate random number in the range of 0 to n (signed 16-bit integer). Result set in $RAND variable. For example:

#!/bin/bash

random()
{
    local range=${1:-1}

    RAND=`od -t uI -N 4 /dev/urandom | awk '{print $2}'`
    let "RAND=$RAND%($range+1)"
}

n=10
while [ $(( n -=1 )) -ge "0" ]; do
    random 500
    echo "$RAND"
done

A bash function that uses perl to generate a random number of n digits. Specify either the number of digits or a template of n 0s.

rand() {
  perl -E '$ARGV[0]||=""; $ARGV[0]=int($ARGV[0])||length($ARGV[0]); say join "", int(rand(9)+1)*($ARGV[0]?1:0), map { int(rand(10)) } (0..($ARGV[0]||0)-2)' $1
}

Usage:

$ rand 3
381
$ rand 000
728

Demonstration of calling rand n, for n between 0 and 15:

$ for n in {0..15}; do printf "%02d: %s\n" $n $(rand $n); done
00: 0
01: 3
02: 98
03: 139
04: 1712
05: 49296
06: 426697
07: 2431421
08: 82727795
09: 445682186
10: 6368501779
11: 51029574113
12: 602518591108
13: 5839716875073
14: 87572173490132
15: 546889624135868

Demonstration of calling rand n, for n a template of 0s between length 0 and 15

$ for n in {0..15}; do printf "%15s :%02d: %s\n" $(printf "%0${n}d" 0) $n $(rand $(printf "%0${n}d" 0)); done
              0 :00: 0
              0 :01: 0
             00 :02: 70
            000 :03: 201
           0000 :04: 9751
          00000 :05: 62237
         000000 :06: 262860
        0000000 :07: 1365194
       00000000 :08: 83953419
      000000000 :09: 838521776
     0000000000 :10: 2355011586
    00000000000 :11: 95040136057
   000000000000 :12: 511889225898
  0000000000000 :13: 7441263049018
 00000000000000 :14: 11895209107156
000000000000000 :15: 863219624761093

I like this trick:

echo ${RANDOM:0:1} # random number between 1 and 9
echo ${RANDOM:0:2} # random number between 1 and 99

...


There is $RANDOM. I don't know exactly how it works. But it works. For testing, you can do :

echo $RANDOM

Use $RANDOM. It's often useful in combination with simple shell arithmetic. For instance, to generate a random number between 1 and 10 (inclusive):

$ echo $((1 + $RANDOM % 10))
3

The actual generator is in variables.c, the function brand(). Older versions were a simple linear generator. Version 4.0 of bash uses a generator with a citation to a 1985 paper, which presumably means it's a decent source of pseudorandom numbers. I wouldn't use it for a simulation (and certainly not for crypto), but it's probably adequate for basic scripting tasks.

If you're doing something that requires serious random numbers you can use /dev/random or /dev/urandom if they're available:

$ dd if=/dev/urandom count=4 bs=1 | od -t d

Reading from /dev/random or /dev/urandom character special files is the way to go.

These devices return truly random numbers when read and are designed to help application software choose secure keys for encryption. Such random numbers are extracted from an entropy pool that is contributed by various random events. {LDD3, Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman]

These two files are interface to kernel randomization, in particular

void get_random_bytes_arch(void* buf, int nbytes)

which draws truly random bytes from hardware if such function is by hardware implemented (usually is), or it draws from entropy pool (comprised of timings between events like mouse and keyboard interrupts and other interrupts that are registered with SA_SAMPLE_RANDOM).

dd if=/dev/urandom count=4 bs=1 | od -t d

This works, but writes unneeded output from dd to stdout. The command below gives just the integer I need. I can even get specified number of random bits as I need by adjustment of the bitmask given to arithmetic expansion:

me@mymachine:~/$ x=$(head -c 1 /dev/urandom > tmp && hexdump 
                         -d tmp | head -n 1 | cut -c13-15) && echo $(( 10#$x & 127 ))

If you are using a linux system you can get a random number out of /dev/random or /dev/urandom. Be carefull /dev/random will block if there are not enough random numbers available. If you need speed over randomness use /dev/urandom.

These "files" will be filled with random numbers generated by the operating system. It depends on the implementation of /dev/random on your system if you get true or pseudo random numbers. True random numbers are generated with help form noise gathered from device drivers like mouse, hard drive, network.

You can get random numbers from the file with dd


I have taken a few of these ideas and made a function that should perform quickly if lots of random numbers are required.

calling od is expensive if you need lots of random numbers. Instead I call it once and store 1024 random numbers from /dev/urandom. When rand is called, the last random number is returned and scaled. It is then removed from cache. When cache is empty, another 1024 random numbers is read.

Example:

rand 10; echo $RET

Returns a random number in RET between 0 and 9 inclusive.

declare -ia RANDCACHE
declare -i RET RAWRAND=$(( (1<<32)-1 ))

function rand(){  # pick a random number from 0 to N-1. Max N is 2^32
  local -i N=$1
  [[ ${#RANDCACHE[*]} -eq 0 ]] && { RANDCACHE=( $(od -An -tu4 -N1024 /dev/urandom) ); }  # refill cache
  RET=$(( (RANDCACHE[-1]*N+1)/RAWRAND ))  # pull last random number and scale
  unset RANDCACHE[${#RANDCACHE[*]}-1]     # pop read random number
};

# test by generating a lot of random numbers, then effectively place them in bins and count how many are in each bin.

declare -i c; declare -ia BIN

for (( c=0; c<100000; c++ )); do
  rand 10
  BIN[RET]+=1  # add to bin to check distribution
done

for (( c=0; c<10; c++ )); do
  printf "%d %d\n" $c ${BIN[c]} 
done

UPDATE: That does not work so well for all N. It also wastes random bits if used with small N. Noting that (in this case) a 32 bit random number has enough entropy for 9 random numbers between 0 and 9 (10*9=1,000,000,000 <= 2*32) we can extract multiple random numbers from each 32 random source value.

#!/bin/bash

declare -ia RCACHE

declare -i RET             # return value
declare -i ENT=2           # keep track of unused entropy as 2^(entropy)
declare -i RND=RANDOM%ENT  # a store for unused entropy - start with 1 bit

declare -i BYTES=4         # size of unsigned random bytes returned by od
declare -i BITS=8*BYTES    # size of random data returned by od in bits
declare -i CACHE=16        # number of random numbers to cache
declare -i MAX=2**BITS     # quantum of entropy per cached random number
declare -i c

function rand(){  # pick a random number from 0 to 2^BITS-1
  [[ ${#RCACHE[*]} -eq 0 ]] && { RCACHE=( $(od -An -tu$BYTES -N$CACHE /dev/urandom) ); }  # refill cache - could use /dev/random if CACHE is small
  RET=${RCACHE[-1]}              # pull last random number and scale
  unset RCACHE[${#RCACHE[*]}-1]  # pop read random number
};

function randBetween(){
  local -i N=$1
  [[ ENT -lt N ]] && {  # not enough entropy to supply ln(N)/ln(2) bits
    rand; RND=RET       # get more random bits
    ENT=MAX             # reset entropy
  }
  RET=RND%N  # random number to return
  RND=RND/N  # remaining randomness
  ENT=ENT/N  # remaining entropy
};

declare -ia BIN

for (( c=0; c<100000; c++ )); do
  randBetween 10
  BIN[RET]+=1
done

for c in ${BIN[*]}; do
  echo $c
done

Wanted to use /dev/urandom without dd and od

function roll() { local modulus=${1:-6}; echo $(( 1 + 0x$(env LC_CTYPE=C tr -dc '0-9a-fA-F' < /dev/urandom | head -c5 ) % $modulus )); }

Testing

$ roll
5
$ roll 12
12

Just how random is it?

$ (echo "count roll percentage"; i=0; while [ $i -lt 10000 ]; do roll; i=$((i+1)); done | sort | uniq -c | awk '{print $0,($1/10000*100)"%"}') | column -t
count  roll  percentage
1625   1     16.25%
1665   2     16.65%
1646   3     16.46%
1720   4     17.2%
1694   5     16.94%
1650   6     16.5%

Maybe I am a bit too late, but what about using jot to generate a random number within a range in Bash?

jot -r -p 3 1 0 1

This generates a random (-r) number with 3 decimal places precision (-p). In this particular case, you'll get one number between 0 and 1 (1 0 1). You can also print sequential data. The source of the random number, according to the manual, is:

Random numbers are obtained through arc4random(3) when no seed is specified, and through random(3) when a seed is given.


You can also use shuf (available in coreutils).

shuf -i 1-100000 -n 1

Try this from your shell:

$ od -A n -t d -N 1 /dev/urandom

Here, -t d specifies that the output format should be signed decimal; -N 1 says to read one byte from /dev/urandom.


you can also get random number from awk

awk 'BEGIN {
   # seed
   srand()
   for (i=1;i<=1000;i++){
     print int(1 + rand() * 100)
   }
}'

What about:

perl -e 'print int rand 10, "\n"; '

Based on the great answers of @Nelson, @Barun and @Robert, here is a Bash script that generates random numbers.

  • Can generate how many digits you want.
  • each digit is separately generated by /dev/urandom which is much better than Bash's built-in $RANDOM
#!/usr/bin/env bash

digits=10

rand=$(od -A n -t d -N 2 /dev/urandom |tr -d ' ')
num=$((rand % 10))
while [ ${#num} -lt $digits ]; do
  rand=$(od -A n -t d -N 1 /dev/urandom |tr -d ' ')
  num="${num}$((rand % 10))"
done
echo $num

bash 5.1 introduces a new variable, SRANDOM, which gets its random data from the system's entropy engine and so is not linear and cannot be reseeded to get an identical random sequence. This variable can be used as a substitute for RANDOM for generating more random numbers.

$ echo $((1 + SRANDOM % 10))
4

Please see $RANDOM:

$RANDOM is an internal Bash function (not a constant) that returns a pseudorandom integer in the range 0 - 32767. It should not be used to generate an encryption key.


Examples related to bash

Comparing a variable with a string python not working when redirecting from bash script Zipping a file in bash fails How do I prevent Conda from activating the base environment by default? Get first line of a shell command's output Fixing a systemd service 203/EXEC failure (no such file or directory) /bin/sh: apt-get: not found VSCode Change Default Terminal Run bash command on jenkins pipeline How to check if the docker engine and a docker container are running? How to switch Python versions in Terminal?

Examples related to shell

Comparing a variable with a string python not working when redirecting from bash script Get first line of a shell command's output How to run shell script file using nodejs? Run bash command on jenkins pipeline Way to create multiline comments in Bash? How to do multiline shell script in Ansible How to check if a file exists in a shell script How to check if an environment variable exists and get its value? Curl to return http status code along with the response docker entrypoint running bash script gets "permission denied"

Examples related to random

How can I get a random number in Kotlin? scikit-learn random state in splitting dataset Random number between 0 and 1 in python In python, what is the difference between random.uniform() and random.random()? Generate random colors (RGB) Random state (Pseudo-random number) in Scikit learn How does one generate a random number in Apple's Swift language? How to generate a random string of a fixed length in Go? Generate 'n' unique random numbers within a range What does random.sample() method in python do?