1

I am attempting to create a random number generator that generates a number between 1 and 99 but not any number that has already been generated.

In the script array1 contains the numbers already generated. To make it easier to test I have reduced the random number range to 0 - 14 and manually created an array.

I am quite new to bash scripting and am picking it up with a couple of books and the internet.

I have tried a mixture of ideas, the one that seems to make most sense is

array1=( 1 2 3 6 7 8 9 10 11 12 13 )
func1() {
    for var in "${array1[@]}"
    do
      echo $var
    done
}
rnd=$[ $RANDOM % 14 ]
until [ $rnd != func1 ]
    do
        rnd=$[ $RANDOM % 14 ]
    done
echo $rnd

however I know the problem is on line 9 the shell sees the following code:

until [ $rnd != 1 2 3 6 7 8 9 10 11 12 13 ]

I know that the solution is that line 9 needs to be:

until [ $rnd != 1 ] && [ $rnd != 2 ] && [ $rnd != 3 ] && ...

I just don't know how to make this happen automatically from the array. The array does vary in length depending on how many numbers have been generated.

Any help will be greatly appreciated!

2
  • 1
    Look up "random permutation" and "Knuth shuffle". Commented Jan 3, 2012 at 1:23
  • The form rnd=$[ $RANDOM % 14 ] is deprecated. Use ((rnd = $RANDOM % 14)) instead. If you have the shuf utility, you can do shuf -i 0-14. Commented Jan 4, 2012 at 22:10

3 Answers 3

1

This is something that I found difficulty doing in bash. The approach I came up with is to have func1() return true or false and modify the array to remove the number that has been picked.

array=( {1..15} )
func1() {
   local pick="$1"
   found=1
   total=${#array[@]}
   for ((i=0;i<total;i++)); do 
      if (( pick == ${array[i]} )); then
         echo $pick
         array=( ${array[@]:0:i} ${array[@]:((i + 1)):$total})
         found=0
         break
      fi
   done
   return $found
}
numbers=3
for ((x=0;x<numbers;x++)); do 
   until func1 $(( $RANDOM % ( ${#array[@]} ) )); do 
      continue 
   done 
done
Sign up to request clarification or add additional context in comments.

4 Comments

have you tested it? I get a syntax error near unexpected token (': until func1 (( $RANDOM % ${array[-1]} )); do in bash 3
Looks like I left out a "$" when I copied it over. I wrote all that in one line before converting it for readability.
You can omit the (()) and dollar sign inside the array slice: array=( ${array[@]:0:i} ${array[@]:i + 1:total}). You can also unset an array element, but that creates a sparse array and you have to iterate over its indices using ${!array[@]}.
@DennisWilliamson Thanks for the info on ${!array[@]}. I didn't use unset because I was unaware of ${!array[@]}.
1

As noted in one of the comments, using the Knuth Shuffle is an excellent way to do this

#!/bin/bash

shuffle() {
   local i tmp size max rand
   # Code from http://mywiki.wooledge.org/BashFAQ/026
   # $RANDOM % (i+1) is biased because of the limited range of $RANDOM
   # Compensate by using a range which is a multiple of the array size.
   size=${#array[*]}
   max=$(( 32768 / size * size ))

   for ((i=size-1; i>0; i--)); do
      while (( (rand=$RANDOM) >= max )); do :; done
      rand=$(( rand % (i+1) ))
      tmp=${array[i]} array[i]=${array[rand]} array[rand]=$tmp
   done
}

# Fill an array with values 1 to 99
array=({1..99});

# Shuffle the array at random
shuffle

# Echo shuffled array
echo ${array[@]}

Output

$ ./knuth
58 78 6 37 84 79 81 43 50 25 49 56 99 41 26 15 86 11 96 90 76 46 92 70 87 27 33 91 1 2 73 97 65 69 42 32 39 67 72 52 36 64 24 88 60 35 83 89 66 30 4 53 57 28 75 48 40 74 18 23 45 61 20 31 21 16 68 80 62 8 98 14 7 19 47 55 22 85 59 17 77 10 63 93 51 54 95 82 94 9 44 38 13 71 34 29 5 3 12

Comments

0

You can also use the -R switch to sort, if your version of sort supports it:

for x in {1..99} ; do echo $x ; done | sort -R

1 Comment

printf '%s\n' {1..99} | sort -R

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.