Bash Shell Generate Random Numbers

Posted on in Categories last updated April 27, 2010

How do I create or generate random numbers (sequence of numbers that lack any pattern), under Bash shell?

The bash shell offers $RANDOM variable (it also works with ksh). From the bash man page:

Each time this is referenced, a random integer between 0 and 32767 is generated. The sequence of random numbers may be initialized by assigning a value to RANDOM. If RANDOM is unset, it loses its special properties, even if it is subsequently reset.

To view $RANDOM, enter:
$ echo $RANDOM
Sample outputs:

11799

You can use the bash loop as follows to test random numbers:

for i in {1..5}; do echo $RANDOM; done

Sample outputs:

32340
18591
32100
15165
19743

You can store it to a variable as follows:

#!/bin/bash
 n=$RANDOM
 echo "My move: trying $n..."

You can have a random integer number within a certain range as follows:

n=$RANDOM
# display a random integer <= 200
echo $(( r %= 200 ))
# display random number between 100 and 200.
echo $((RANDOM%200+100))

Here is a sample shell script to find out random TCP port:

#!/bin/bash
# Set a trap to detect spam bots at port 80
 
# Find out random unused TCP port 
findRandomTcpPort(){
	port=$(( 100+( $(od -An -N2 -i /dev/random) )%(1023+1) ))
	while :
	do
		(echo >/dev/tcp/localhost/$port) &>/dev/null &&  port=$(( 100+( $(od -An -N2 -i /dev/random) )%(1023+1) )) || break
	done
	echo "$port"
}
 
p=$(findRandomTcpPort)
echo "Setting Honeypot @ port 80 and real Apache server at port $p..."
# setHoneypot 80 
# setApache $p

Another shell script to setup a random wallpaper. You can call this one from your crontab:

#!/bin/bash
# get images
files=(/nas/download/share/fun/images/wallpapers/*.png) 
# find out random one
n=${#files[@]}           
wallpaper="${files[RANDOM % n]}"
# Kde3 command (may not work with kde4)
# dcop kdesktop KBackgroundIface setWallpaper "$wallpaper" 5
 
# Gnome command
gconftool-2 --type string --set /desktop/gnome/background/picture_filename "$wallpaper"

Using /dev/urandom or /dev/random

The character special files /dev/random and /dev/urandom provide an interface to the kernel’s random number generator. You can use /dev/urandom as follows:
$ od -vAn -N4 -tu4 < /dev/urandom
Sample outputs:

2494028411

You can use /dev/random as follows:
$ od -An -N2 -i /dev/random
Sample outputs:

62362

Recommended readings:

See the following man pages:
man 4 random
man bash
man od

Posted by: Vivek Gite

The author is the creator of nixCraft and a seasoned sysadmin and a trainer for the Linux operating system/Unix shell scripting. He has worked with global clients and in various industries, including IT, education, defense and space research, and the nonprofit sector. Follow him on Twitter, Facebook, Google+.

Share this on (or read 19 comments/add one below):

19 comment

  1. Thanks for the tips. Two mistake though:
    – ‘echo $(( r %= 200 ))’ should be ‘echo $(( n %= 200 ))’
    – ‘echo $((RANDOM%200+100))’ return a number between 100 and 300, not 100 and 200 as commented above.

    1. The example involving 200 is not a uniform distribution. The mapping function used is f(x) = x module 200. This input, x, is a uniform distribution. The output f(x) is not because the the size of the domain is a power of 2 and the size of the range is 200. if f(x) were random, the size of the domain would be a multiple of the size of the range. A power of 2 is never a multiple of 200. The following would be random: while (set I to $RANDOM) {if i < 200 then {echo $i; break;} }.

  2. Nice topic.
    Precision:

    echo $(( n %= 200 ))

    Will return an integer strictly less than 200.

    I think that If you want to include 200, you could use:

    echo $(( n %= 200 + 1))

    But then, [n] will never be zero, it will belong to [1;200]

  3. Like the man page excerpt above says, you can initialize the sequence by assigning an arbitrary number to RANDOM before using it. If you don’t want the same ‘random’ sequence each time you run the script, you should seed RANDOM by assigning an arbitrary number before using it. The process ID works well:

    RANDOM=$$

  4. OpenSSL can also be used as a source of random numbers, and is a good idea if the numbers are going to be used for cryptographic key generation or nonces. The generator used by OpenSSL uses a FIPS 140 approved algorithm and has been widely tested and reviewed.

    OpenSSL on Unix systems will leverage available entropy from the OS RNG as part of it’s seed/start process.

    Here are some sample commands – quoted from the “OpenSSL Command-line HOWTO”:

    # write 128 random bytes of base64-encoded data to stdout
    openssl rand -base64 128

    # write 1024 bytes of binary random data to a file
    openssl rand -out random-data.bin 1024

    Cheers, Erik
    ArtofInfoSec.com

  5. vivek,
    There is a bug here:

    # display random number between 100 and 200.
    echo $((RANDOM%200+100))

    This will display random number between 100 and 300 (not 200)

    If you want to display random number between 100 and 200, use:

    echo $((RANDOM%100+100))

    Would you modify yor code above?

  6. Works good:
    echo $(( RANDOM% ($maximal – $minimal) + $minimal ))

    example: maximal=10 minimal=5 try it ;)

    Or if you want numbers between 5 – 10, you can do this:
    echo $(( RANDOM% 5 + 5 ))
    5 – minimum, maximum is +5 bigger

  7. Hi Vivek,

    You may be overwhelmed or overloaded,
    but you will also find that this page does not meet your quality standard.

    1) As Dago said:
    #To get random integer number between x and y, x and y beeing included as in [x;y] notation, use:
    echo $((x + RANDOM%(y-x+1)))

    2) Typo
    There is still a typo here: echo $(( r %= 200 ))
    Should be: echo $(( n %= 200 ))

    3) Misunderstanding
    Why do you use “%=” where “%” will be appropriate ?
    That is: echo $(( n %= 200 ))
    Should be: echo $(( n % 200 ))

    KUTGW, I really appreciate your site – as usual, great work.

    — Philippe

  8. Nice and instructive post!
    I was looking for a way to seed the $RANDOM-ness in bash, and I found this can be done by setting the $RANDOM variable:
    $ RANDOM=1
    $ echo $RANDOM
    16807
    $ echo $RANDOM
    15089
    $ RANDOM=1
    $ echo $RANDOM
    16807
    $ echo $RANDOM
    15089

    May be a good way for seeding randomness would be using time:
    $ RANDOM=$(date +%s)

    Thanks a lot!

  9. Nanosecond semi-random number generator

    date +’%N’

    Can also be used as $RANDOM shuffler:

    RANDOM=$(date +’%N’)

    $ RANDOM=$(date +’%N’)
    $ echo $RANDOM
    13967
    $ RANDOM=$(date +’%N’)
    $ echo $RANDOM
    27211

  10. Random entropy pool init with subsequent selection of some text to echo. ‘+’ should never hit (%3 + 1 == 1 to 3). Output will be 1,2 or 3.

    RANDOM=`date +%s%N | cut -b14-19`;
    case $[$RANDOM % 3 + 1] in 1) echo ‘1’;; 2) echo ‘2’;; 3) echo ‘3’;; *) echo ‘+’;; esac

  11. I find ‘shuf’ to be a good solution. You can specify the range and how many numbers you want back, as well as a random source to make it repeatable when testing.

    Example:

    RANDOM=$(shuf -i 1-1000 -n 1)

    although it’s probably as good as using ‘od’.

    Using $RANDOM works, but technically won’t give you a very even distribution (as it’s between 0 and 32767 before you % 100 it or whatever).

Leave a Comment