2

In GENERAL, on Linux, UNIX, BSD, cygwin systems, how can I get random numbers from /dev/urandom inside a given range, example:

217 < X < 34523

OR other example:

36856 < X < 76543 

I am afraid to even try to search for solutions, since this is not just "google and first hit", because it has to be 100% correct from randomness point of view.

I tried to write it my own:

$ cat randomfournumbers.sh
#!/bin/bash

working=true
howmanyneeded=0

while "$working"; do
fivedigit=$(tr -cd "[:digit:]"</dev/urandom|fold -w5|head -1)

        if [ "$fivedigit" -ge 300 ]; then
                if [ "$fivedigit" -le 33000 ]; then

                        echo "$fivedigit"
                        howmanyneeded=$((howmanyneeded+1))

                        if [ "$howmanyneeded" -ge 4 ]; then
                                working=false
                        fi
                fi
        fi
done
$ sh randomfournumbers.sh
11442
26742
13905
23547
$

But afaik cryptography, randomness.. I am sure it contains an error that I cannot see (no problem with urandom, rather the logic).

  • 4
    echo $(( ( RANDOM % (34523-217) ) + 217+1)) – Rui F Ribeiro Dec 30 '17 at 21:10
  • 1
    In general, you use a library. Or start by considering the actual algorithm you need to fill the requirements you have, and only then implement it in some programming language. – ilkkachu Dec 30 '17 at 22:13
  • 1
    I'm voting to close this question as off-topic because it's about mathematics, not Unix, and would be better off on math.SE or crypto.SE. – ilkkachu Dec 30 '17 at 22:14
  • @ilkkachu, the question asks how to obtain specific output from a specific special file (/dev/urandom), on specific Unix-like operating systems or environments ("Linux, UNIX, BSD, cygwin systems"). I am amazed that you regard it as off-topic. – sampablokuper Jan 6 '18 at 19:26
  • @sampablokuper, urandom gives random byte values. An interface like that is not unique to Unix, other systems have that too, e.g. CryptGenRandom on Windows, RAND_bytes in OpenSSL. All that's Unix-specific here is the name of the interface, and we already know that. After that, it's just mathematics on how to turn random bytes to random numbers in a given range, while getting the required properties (uniform distribution). – ilkkachu Jan 6 '18 at 20:51
1

I think shuf would be a better tool for this purpose.

Example:

$ shuf -i 217-34523 -n 1
11623

But if you really want to use /dev/urandom, this should do the work:

random_numbers() {
  a="$1"
  b="$2"
  lim="$3"
  count="0"

  while :; do
    num=$(tr -dc '0-9\n' < /dev/urandom | grep -Pom1 "^\\d{${#a},${#b}}")
    if [ "$num" -ge "$a" ] && [ "$num" -le "$b" ]; then
      echo "$num"
      count="$((count + 1))"
      [ "$count" -ge "$lim" ] && break
    fi
  done
}

Example:

$ random_numbers 36856 76543 5
75544
55383
43024
72678
63635
0

This script does the job:

#!/bin/bash

log2x(){
    local bytes=0 t=$1
    while ((t>0)); do
    ((t=t>>8,bytes++))
    done
    echo "$bytes"
}

mkrandom(){
    while :; do
    hexrandom=$(dd if=/dev/urandom bs=1 count=$bytes 2>/dev/null | xxd -p)
    (( 16#$hexrandom < range*mult )) && break
    done
    echo "$(( (16#$hexrandom%range)+min ))"
}

if (($#==3)); then
    min=$2 max=$(($3+1))
else
    min=217 max=34523
fi
range=$((max-min+1))

bytes=$(log2x "$range")
maxvalue=$(((1<<($bytes*8))-1))
mult=$((maxvalue/range))
#printf "maxvalue=%d mult=%d range=%d\n" "$maxvalue" "$mult" "$range"


while ((i++<$1)); do
    mkrandom 
done

Call as ./script count min max:

./script 5 23 323
261
319
189
204
93

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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