Random element from array greater than 32767 in bash

Availability:

mapfile -t words < <( head -10000 /usr/share/dict/words)
echo "${#words[@]}" #10000
r=$(( $RANDOM % ${#words[@]} ))
echo "$r ${words[$r]}"

      

Pick a random word from an array of 10k words.

But having an array of size 32767 (for example, whole files 200k + words), it stops working because $RANDOM

- only up to 32767. From man bash

:

Each time this parameter is referenced, a random integer from 0 to 32767 is generated.

mapfile -t words < /usr/share/dict/words
echo "${#words[@]}" # 235886
r=$(( $RANDOM % ${#words[@]} )) #how to change this?
echo "$r ${words[$r]}"

      

No need to use some perl, as perl -plE 's/.*/int(rand()*$_)/e'

not every system has perl. Looking for the simplest solution - and also don't care about true randomness - this isn't for crypto. :)

+3


source to share


2 answers


One possible solution is to do some math with the result $RANDOM

:

big_random=`expr $RANDOM \* 32767 + $RANDOM`

      

Another is to use it $RANDOM

once to select a block of the input file, then $RANDOM

again to select a line from that block.



Note that it is $RANDOM

not possible to specify a range. %

gives uneven results. Further discussion: How do I generate a random number in Bash?

As an aside, it doesn't seem particularly wise to read everything words

in memory. If you won't be doing a lot of re-access to this data structure, think about it without parsing the entire file at once.

+1


source


If shuf

available on your system ...

r=$(shuf -i 0-${#words[@]} -n 1)

      

If not, you can use $RANDOM

multiple times and combine the results to get a number with enough digits to suit your needs. You should be concatenating, not adding, as adding random numbers will not result in an even distribution (just like throwing two random stamps would result in a total of 7 more often than just 1).



For example:

printf -v r1 %05d $RANDOM
printf -v r2 %05d $RANDOM
printf -v r3 %05d $RANDOM
r4=${r1:1}${r2:1}${r3:1}
r=$(( $r4 % ${#words[@]} ))

      

Operators printf

are used to ensure that leading zeros are preserved; a parameter -v

is a hidden gem that allows a variable to be assigned a value (which, among other things, avoids being used eval

in many useful real-world cases). The first digit is in each r1

, r2

and r3

is separated as it can only be 0, 1, 2, or 3.

+1


source







All Articles