How to generate random number in Bash?

前端 未结 11 1443
青春惊慌失措
青春惊慌失措 2020-11-27 09:33

How to generate a random number within a range in Bash?

相关标签:
11条回答
  • 2020-11-27 10:18

    Try this from your shell:

    $ od -A n -t d -N 1 /dev/urandom
    

    Here, -t d specifies that the output format should be signed decimal; -N 1 says to read one byte from /dev/urandom.

    0 讨论(0)
  • 2020-11-27 10:19

    Please see $RANDOM:

    $RANDOM is an internal Bash function (not a constant) that returns a pseudorandom integer in the range 0 - 32767. It should not be used to generate an encryption key.

    0 讨论(0)
  • 2020-11-27 10:19

    Reading from /dev/random or /dev/urandom character special files is the way to go.

    These devices return truly random numbers when read and are designed to help application software choose secure keys for encryption. Such random numbers are extracted from an entropy pool that is contributed by various random events. {LDD3, Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman]

    These two files are interface to kernel randomization, in particular

    void get_random_bytes_arch(void* buf, int nbytes)
    

    which draws truly random bytes from hardware if such function is by hardware implemented (usually is), or it draws from entropy pool (comprised of timings between events like mouse and keyboard interrupts and other interrupts that are registered with SA_SAMPLE_RANDOM).

    dd if=/dev/urandom count=4 bs=1 | od -t d
    

    This works, but writes unneeded output from dd to stdout. The command below gives just the integer I need. I can even get specified number of random bits as I need by adjustment of the bitmask given to arithmetic expansion:

    me@mymachine:~/$ x=$(head -c 1 /dev/urandom > tmp && hexdump 
                             -d tmp | head -n 1 | cut -c13-15) && echo $(( 10#$x & 127 ))
    
    | improve this answer | |
    0 讨论(0)
  • 2020-11-27 10:22

    you can also get random number from awk

    awk 'BEGIN {
       # seed
       srand()
       for (i=1;i<=1000;i++){
         print int(1 + rand() * 100)
       }
    }'
    
    0 讨论(0)
  • 2020-11-27 10:29

    I have taken a few of these ideas and made a function that should perform quickly if lots of random numbers are required.

    calling od is expensive if you need lots of random numbers. Instead I call it once and store 1024 random numbers from /dev/urandom. When rand is called, the last random number is returned and scaled. It is then removed from cache. When cache is empty, another 1024 random numbers is read.

    Example:

    rand 10; echo $RET
    

    Returns a random number in RET between 0 and 9 inclusive.

    declare -ia RANDCACHE
    declare -i RET RAWRAND=$(( (1<<32)-1 ))
    
    function rand(){  # pick a random number from 0 to N-1. Max N is 2^32
      local -i N=$1
      [[ ${#RANDCACHE[*]} -eq 0 ]] && { RANDCACHE=( $(od -An -tu4 -N1024 /dev/urandom) ); }  # refill cache
      RET=$(( (RANDCACHE[-1]*N+1)/RAWRAND ))  # pull last random number and scale
      unset RANDCACHE[${#RANDCACHE[*]}-1]     # pop read random number
    };
    
    # test by generating a lot of random numbers, then effectively place them in bins and count how many are in each bin.
    
    declare -i c; declare -ia BIN
    
    for (( c=0; c<100000; c++ )); do
      rand 10
      BIN[RET]+=1  # add to bin to check distribution
    done
    
    for (( c=0; c<10; c++ )); do
      printf "%d %d\n" $c ${BIN[c]} 
    done
    

    UPDATE: That does not work so well for all N. It also wastes random bits if used with small N. Noting that (in this case) a 32 bit random number has enough entropy for 9 random numbers between 0 and 9 (10*9=1,000,000,000 <= 2*32) we can extract multiple random numbers from each 32 random source value.

    #!/bin/bash
    
    declare -ia RCACHE
    
    declare -i RET             # return value
    declare -i ENT=2           # keep track of unused entropy as 2^(entropy)
    declare -i RND=RANDOM%ENT  # a store for unused entropy - start with 1 bit
    
    declare -i BYTES=4         # size of unsigned random bytes returned by od
    declare -i BITS=8*BYTES    # size of random data returned by od in bits
    declare -i CACHE=16        # number of random numbers to cache
    declare -i MAX=2**BITS     # quantum of entropy per cached random number
    declare -i c
    
    function rand(){  # pick a random number from 0 to 2^BITS-1
      [[ ${#RCACHE[*]} -eq 0 ]] && { RCACHE=( $(od -An -tu$BYTES -N$CACHE /dev/urandom) ); }  # refill cache - could use /dev/random if CACHE is small
      RET=${RCACHE[-1]}              # pull last random number and scale
      unset RCACHE[${#RCACHE[*]}-1]  # pop read random number
    };
    
    function randBetween(){
      local -i N=$1
      [[ ENT -lt N ]] && {  # not enough entropy to supply ln(N)/ln(2) bits
        rand; RND=RET       # get more random bits
        ENT=MAX             # reset entropy
      }
      RET=RND%N  # random number to return
      RND=RND/N  # remaining randomness
      ENT=ENT/N  # remaining entropy
    };
    
    declare -ia BIN
    
    for (( c=0; c<100000; c++ )); do
      randBetween 10
      BIN[RET]+=1
    done
    
    for c in ${BIN[*]}; do
      echo $c
    done
    
    0 讨论(0)
提交回复
热议问题