How to generate a random number within a range in Bash?
How to generate a random number within a range in Bash?
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
Please see $RANDOM:
$RANDOMis 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.
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)
}
}'
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
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
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 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 125 (113-1+13), with reasonable random entropy.
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.
Based on the great answers of @Nelson, @Barun and @Robert, here is a Bash script that generates random numbers.
/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
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
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%
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 :)
You can use a seed, see documentation:
RANDOM=$(date +%s%N | cut -b10-19)
echo $(( $RANDOM % 100 + 1 ))
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
Pure Bash random number without moduloing
lowerRange=10 # inclusive
upperRange=20 # exclusive
randomNumber=$(( RANDOM * ( upperRange - lowerRange) / 32767 + lowerRange ))
Here is a function I wrote which will output a random number in a desired range>
Description:
random <min> <max>Generate a random number from
mintomax, inclusive. Bothminandmaxcan be positive OR negative numbers, and the generated random number can be negative too, so long as the range(max - min + 1)is less than or equal to32767. Max must be >= min.
The core of it is this:
random() {
min="$1"
max="$2"
range=$((max - min + 1))
rand=$((min + (RANDOM % range)))
echo "$rand"
}
Usage:
# general form: obtain a random number between min and max, inclusive
random <min> <max>
# Example: obtain a random number from -10 to 10, inclusive
random -10 10
This works from the bash built-in variable RANDOM, which probably just uses C rand() under the hood, since they both have a max value of 32767--see:
For the bash documentation, see man bash:
RANDOMEach time this parameter is referenced, a random integer between
0and32767is generated. The sequence of random numbers may be initialized by assigning a value toRANDOM. IfRANDOMisunset, it loses its special properties, even if it is subsequently reset.
sourceable version of the scriptHere is a much more robust version of my random function above. It includes full error checking, bounds checking, a help menu via random --help or random -h, and a special run_check feature which allows you to source OR run this script so that you can source it to import the random function into any other script--just like you can do in Python!
random.sh <-- click this link to always get the latest version from my eRCaGuy_dotfiles repo.
RETURN_CODE_SUCCESS=0
RETURN_CODE_ERROR=1
HELP_STR="\
Generate a random integer number according to the usage styles below.
USAGE STYLES:
'random'
Generate a random number from 0 to 32767, inclusive (same as bash variable 'RANDOM').
'random <max>'
Generate a random number from 0 to 'max', inclusive.
'random <min> <max>'
Generate a random number from 'min' to 'max', inclusive. Both 'min' and 'max' can be
positive OR negative numbers, and the generated random number can be negative too, so
long as the range (max - min + 1) is less than or equal to 32767. Max must be >= min.
This file is part of eRCaGuy_dotfiles: https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles
"
print_help() {
echo "$HELP_STR" | less -RFX
}
# Get a random number according to the usage styles above.
# See also `utils_rand()` in utilities.c:
# https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/c/utilities.c#L176
random() {
# PARSE ARGUMENTS
# help menu
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
print_help
exit $RETURN_CODE_SUCCESS
fi
# 'random'
if [ $# -eq 0 ]; then
min=0
max="none"
# 'random max'
elif [ $# -eq 1 ]; then
min=0
max="$1"
# 'random min max'
elif [ $# -eq 2 ]; then
min="$1"
max="$2"
else
echo "ERROR: too many arguments."
exit "$RETURN_CODE_ERROR"
fi
# CHECK FOR ERRORS
if [ "$max" = "none" ]; then
rand="$RANDOM"
echo "$rand"
exit "$RETURN_CODE_SUCCESS"
fi
if [ "$max" -lt "$min" ]; then
echo "ERROR: max ($max) < min ($min). Max must be >= min."
exit "$RETURN_CODE_ERROR"
fi
# CALCULATE THE RANDOM NUMBER
# See `man bash` and search for `RANDOM`. This is a limitation of that value.
RAND_MAX=32767
range=$((max - min + 1))
if [ "$range" -gt "$RAND_MAX" ]; then
echo "ERROR: the range (max - min + 1) is too large. Max allowed = $RAND_MAX, but actual" \
"range = ($max - $min + 1) = $range."
exit "$RETURN_CODE_ERROR"
fi
# NB: `RANDOM` is a bash built-in variable. See `man bash`, and also here:
# https://stackoverflow.com/a/1195035/4561887
rand=$((min + (RANDOM % range)))
echo "$rand"
}
# Set the global variable `run` to "true" if the script is being **executed** (not sourced) and
# `main` should run, and set `run` to "false" otherwise. One might source this script but intend
# NOT to run it if they wanted to import functions from the script.
# See:
# 1. *****https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/bash/argument_parsing__3_advanced__gen_prog_template.sh
# 1. my answer: https://stackoverflow.com/a/70662049/4561887
# 1. https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/bash/check_if_sourced_or_executed.sh
run_check() {
# This is akin to `if __name__ == "__main__":` in Python.
if [ "${FUNCNAME[-1]}" == "main" ]; then
# This script is being EXECUTED, not sourced
run="true"
fi
}
# ----------------------------------------------------------------------------------------------------------------------
# Main program entry point
# ----------------------------------------------------------------------------------------------------------------------
# Only run main function if this file is being executed, NOT sourced.
run="false"
run_check
if [ "$run" == "true" ]; then
random "$@"
fi
$(((RANDOM % $((upperBound - lowerBound))) + lowerBound))
the random number range is [lowerBound,upperBound)