66

After googling a bit I couldn't find a simple way to use a shell command to generate a random decimal integer number included in a specific range, that is between a minimum and a maximum.

I read about /dev/random, /dev/urandom and $RANDOM, but none of these can do what I need.

Is there another useful command, or a way to use the previous data?

10 Answers 10

36

In the POSIX toolchest, you can use awk:

awk -v min=5 -v max=10 'BEGIN{srand(); print int(min+rand()*(max-min+1))}'

Do not use that as a source to generate passwords or secret data for instance, as with most awk implementations, the number can easily be guessed based on the time that command was run.

With many awk implementations, that command run twice within the same second will generally give you the same output.

117

You can try shuf from GNU coreutils:

shuf -i 1-100 -n 1
  • This also works with Busybox shuf. – cov May 30 '18 at 14:11
  • Works in raspbian and GitBash too. – nPcomp Oct 22 '18 at 17:55
25

jot

On BSD and OSX you can use jot to return a single random (-r) number from the interval min to max, inclusive.

$ min=5
$ max=10
$ jot -r 1 $min $max

Distribution problem

Unfortunately, the range and distribution of randomly generated numbers is influenced by the fact that jot uses double precision floating point arithmetic internally and printf(3) for output format, which causes rounding and truncation issues. Therefore, the interval's min and max are generated less frequently as demonstrated:

$ jot -r 100000 5 10 | sort -n | uniq -c
9918  5
20176 6
20006 7
20083 8
19879 9
9938  10

On OS X 10.11 (El Capitan) this appears to have been fixed:

$ jot -r 100000 5 10 | sort -n | uniq -c
16692 5
16550 6
16856 7
16579 8
16714 9
16609 10  

and...

$ jot -r 1000000 1 10 | sort -n | uniq -c
100430 1
99965 2
99982 3
99796 4
100444 5
99853 6
99835 7
100397 8
99588 9
99710 10

Solving the distribution problem

For older versions of OS X, fortunately there are several workarounds. One is to use printf(3) integer conversion. The only caveat is that the interval maximum now becomes max+1. By using integer formatting, we get fair distribution across the entire interval:

$ jot -w %i -r 100000 5 11 | sort -n | uniq -c
16756 5
16571 6
16744 7
16605 8
16683 9
16641 10

The perfect solution

Finally, to get a fair roll of the dice using the workaround, we have:

$ min=5
$ max_plus1=11  # 10 + 1
$ jot -w %i -r 1 $min $max_plus1

Extra homework

See jot(1) for the gory math and formatting details and many more examples.

11

The $RANDOM variable is normally not a good way to generated good random values. The output of /dev/[u]random need also to be converted first.

An easier way is to use higher level languages, like e.g. python:

To generate a random integer variable between 5 and 10 (5<=N<=10), use

python -c "import random; print random.randint(5,10)"

Do not use this for cryptographic applications.

  • This was useful. Thank you very much :) As signed often has worked with Unix->Solaris 10 the GNU utils are not integrated by default. This worked however. – propatience Feb 22 '17 at 10:29
8

You can get the random number through urandom

head -200 /dev/urandom | cksum

Output:

3310670062 52870

To retrieve the one part of the above number.

head -200 /dev/urandom | cksum | cut -f1 -d " "

Then the output is

3310670062

7

To generate a random integer variable between 5 and 10 (including both), use

echo $(( RANDOM % (10 - 5 + 1 ) + 5 ))

% works as a modulo operator.

There are probably better ways to convert the random variable $RANDOM to a specific range. Do not use this for cryptographic applications or in cases you need real, equal-distributed random variables (like for simulations).

  • 3
    In many shell implementations that do have $RANDOM (especially older ones, especially bash), that's not very random. In most shells, the number is between 0 and 65535, so any range whose width is not a power of two will have probability distribution discrepency. (in this case, numbers 5 to 8 will have a probability of 10923/65536, while 9 and 10 will have a probability of 10922/65536). The wider the range, the bigger the discrepency. – Stéphane Chazelas Jul 4 '14 at 12:39
  • Sorry, that's 32767 not 65535, so the calculation above is wrong (and it's actually worse). – Stéphane Chazelas Jul 4 '14 at 13:05
  • @StéphaneChazelas I had this in mind as I wrote that there are better ways... – jofel Jul 4 '14 at 13:27
3

Maybe the UUID (on Linux) can be used to retrieve the random number

$ cat /proc/sys/kernel/random/uuid
cdd52826-327d-4355-9737-895f58ad11b4

To get the random number between 70 and 100

POSIXLY_CORRECT=1 awk -F - '{print(("0x"$1) % 30 + 70)}
   ' /proc/sys/kernel/random/uuid
3

# echo $(( $RANDOM % 256 )) will produce a "random" number between 0-255 in modern *sh dialects.

  • Looks similar to this other answer from 2 years ago. – Jeff Schaller Nov 24 '16 at 5:24
  • 1
    This is subject to the pigeonhole problem (TL;DR: some outcomes are more likely than others) if, instead of 256, you use a value that doesn't divide 32768 equally. – toon81 Nov 28 '16 at 12:52
2
cat /dev/urandom | tr -dc 'a-fA-F0-9' | fold -w 8 | head -n 1

This will generate an 8 digits long hexadecimal number.

2

To stay entirely within bash and use the $RANDOM variable but avoid the uneven distribution:

#!/bin/bash
range=10 
floor=20

if [ $range -gt 32768 ]; then
echo 'range outside of what $RANDOM can provide.' >&2
exit 1 # exit before entering infinite loop
fi 

max_RANDOM=$(( 2**15/$range*$range ))
r=$RANDOM
until [ $r -lt $max_RANDOM ]; do
r=$RANDOM
done
echo $(( r % $range + $floor ))

This example would provide random numbers from 20 through 29.

  • $r should be initialized to 65535 or other high value to avoid an [: -lt: unary operator expected error. – LawrenceC Jun 10 '18 at 15:27
  • Corrected the $r initialization before the loop test. Thanks @LawrenceC ! – Than Angell Jan 8 at 17:53

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.