1

I need to be able to generate a random number between 2013 and 2044 (inclusive). I have tried the two scripts below, but the output is not quite random in either case. Many numbers are repeated, and others missing. Is there a way to get around this?

Here is the first script:

    i="1"
    x="2014"
    y="2044"
    while [ $i != 32 ]; do
            var=$RANDOM
            var=$[ $x + $var % ($y + 1 -$x) ]
            echo $var
            i=$[$i+1]
     done

Here is the second

    i="1"
    while [ $i != 32 ]; do
            var=$(shuf -i 2014-2044 -n1)
            echo $var
            i=$[$i+1]
    done

Thanks, Ciara

11
  • 1
    shuf is nonstandard. It doesn't exist on OS X, for example. Commented Mar 20, 2014 at 14:59
  • 2
    Please demonstrate how the output you receive differs from what you expect. Quite often properly random data differs from what people intuitively expect. A sample of size 32 is much too small to judge anyway. Commented Mar 20, 2014 at 15:01
  • Could you perhaps use /dev/urandom? dd if=/dev/urandom bs=(small) count=(small) | od -s could get you some values to play with. Commented Mar 20, 2014 at 15:02
  • If what you actually want is a randomized ordering of a range of numbers, please edit the question to clarify this requirement (or just mark as duplicate of one of the many similar questions). Commented Mar 20, 2014 at 15:04
  • 1
    $[...] is a very old syntax; use $((...)) instead. Commented Mar 20, 2014 at 15:13

4 Answers 4

2

When you generate x random numbers in the range [y,z] and x > z-y, you will have some repetitions. You may also encounter some numbers repeated in consecutive slots because when you take mod, a number of those random numbers will actually map onto the same number. If you increase your range, you will notice that the numbers are more random.

Sign up to request clarification or add additional context in comments.

Comments

2

This is the nature of random numbers. Let's try a run with 3100 iterations. We'll expect to get 100 entries for each number in [2014, 2044]:

#!/bin/bash
x=2014
y=2044
n=()
for ((i=1; i<=3100; i++)); do
    (( n[x + RANDOM % (y-x+1)] += 1 ))
done
for ((i=x; i<=y; i++)); do
    printf "%d\t%d\n" $i ${n[i]}
done
2014    95
2015    96
2016    98
2017    87
2018    96
2019    82
2020    111
2021    105
2022    113
2023    100
2024    102
2025    95
2026    89
2027    110
2028    102
2029    93
2030    107
2031    109
2032    115
2033    92
2034    108
2035    96
2036    94
2037    109
2038    91
2039    113
2040    90
2041    123
2042    82
2043    102
2044    95

1 Comment

Thanks @glenn jackman, is there any other way of shuffling through the numbers I want randomly, but so that each one is returned exactly once?
0
seq 2014 2044 | sort -R

This creates the range of numbers with seq, then reorders the lines randomly.

Comments

0

Since you want a random permutation, the random numbers you want to generate are actually indices into a list of the remaining unselected numbers. Something like

unselected=( {2014..2044} )
while (( ${#unselected[@]} > 0 )); do
    # Pick a random index
    index=$(( $RANDOM % ${#unselected[@]} ))
    echo ${unselected[index]}
    # Remove the value at that index
    unset unselected[index]
    unselected=( "${unselected[@]}" )
done

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.