509 Stimmen

Wie erzeugt man eine Zufallszahl in der Bash?

Wie generiert man in der Bash eine Zufallszahl innerhalb eines Bereichs?

5voto

philcolbourn Punkte 3870

Ich habe ein paar dieser Ideen aufgegriffen und eine Funktion entwickelt, die schnell funktionieren sollte, wenn viele Zufallszahlen benötigt werden.

aufrufen od ist teuer, wenn Sie viele Zufallszahlen benötigen. Stattdessen rufe ich es einmal auf und speichere 1024 Zufallszahlen aus /dev/urandom. Wenn rand aufgerufen wird, wird die letzte Zufallszahl zurückgegeben und skaliert. Sie wird dann aus dem Cache entfernt. Wenn der Cache leer ist, werden weitere 1024 Zufallszahlen gelesen.

Beispiel:

rand 10; echo $RET

Liefert eine Zufallszahl in RET zwischen 0 und 9 einschließlich.

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: Das funktioniert nicht so gut für alle N. Außerdem werden bei kleinen N Zufallsbits verschwendet. Eine 32-Bit-Zufallszahl hat (in diesem Fall) genug Entropie für 9 Zufallszahlen zwischen 0 und 9 (10* 9=1,000,000,000 <= 2 *32) können wir mehrere Zufallszahlen aus jedem 32-Zufallswert extrahieren.

#!/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

4voto

Pavlo Bashynskyi Punkte 321

Erzeugt eine Zufallszahl im Bereich von 0 bis n (16-Bit-Ganzzahl mit Vorzeichen). Das Ergebnis wird in der Variablen $RAND gespeichert. Zum Beispiel:

#!/bin/bash

random()
{
    local range=${1:-1}

    RAND=`od -t uI -N 4 /dev/urandom | awk '{print $2}'`
    let "RAND=$RAND%($range+1)"
}

n=10
while [ $(( n -=1 )) -ge "0" ]; do
    random 500
    echo "$RAND"
done

4voto

Eddy763 Punkte 27

Sie können einen Samen verwenden:

RANDOM=$(date +%s%N | cut -b10-19)
echo $(( $RANDOM % 100 + 1 ))

4voto

Gabriel Staples Punkte 20228

Hier ist eine Funktion, die ich geschrieben habe und die eine Zufallszahl in einem gewünschten Bereich ausgibt>

Beschreibung:

random <min> <max>

Generieren Sie eine Zufallszahl aus min a max , einschließlich. Beide min y max können sein positive ODER negative Zahlen sein, und die erzeugte Zufallszahl kann auch negativ sein, also solange der Bereich (max - min + 1) kleiner oder gleich ist als 32767 . Max muss >= min sein.

Der Kern der Sache ist folgender:

random() {
    min="$1"
    max="$2"

    range=$((max - min + 1))
    rand=$((min + (RANDOM % range)))
    echo "$rand"
}

Verwendung:

# general form: obtain a random number between min and max, inclusive
random <min> <max>

# Example: obtain a random number from -10 to 10, inclusive
random -10 10

Dies funktioniert über die eingebaute Bash-Variable RANDOM die wahrscheinlich nur C verwendet rand() unter der Haube, da sie beide einen Maximalwert von 32767 haben - siehe:

  1. https://en.cppreference.com/w/c/numeric/random/rand
  2. https://en.cppreference.com/w/c/numeric/random/RAND_MAX

Für die bash-Dokumentation siehe man bash :

RANDOM

Jedes Mal, wenn dieser Parameter referenziert wird, wird eine zufällige Ganzzahl zwischen 0 y 32767 erzeugt wird. Die Folge von Zufallszahlen kann initialisiert werden, indem ein Wert zugewiesen wird RANDOM . Wenn RANDOM es unset verliert es seine besonderen Eigenschaften, auch wenn es anschließend zurückgesetzt wird.

Robust, lauffähig, source fähige Version des Skripts

Hier ist eine viel robustere Version meiner random Funktion oben. Sie umfasst eine vollständige Fehlerprüfung, eine Begrenzungsprüfung, ein Hilfemenü über random --help o random -h und eine besondere run_check Funktion, die es Ihnen ermöglicht, dieses Skript zu erstellen ODER auszuführen, so dass Sie source es zum Importieren der random Funktion in ein beliebiges anderes Skript einfügen - so wie Sie es in Python tun können!

random.sh <-- Klicken Sie auf diesen Link, um immer die neueste Version von meinem eRCaGuy_dotfiles Repo.

RETURN_CODE_SUCCESS=0
RETURN_CODE_ERROR=1

HELP_STR="\
Generate a random integer number according to the usage styles below.

USAGE STYLES:
    'random'
        Generate a random number from 0 to 32767, inclusive (same as bash variable 'RANDOM').
    'random <max>'
        Generate a random number from 0 to 'max', inclusive.
    'random <min> <max>'
        Generate a random number from 'min' to 'max', inclusive. Both 'min' and 'max' can be
        positive OR negative numbers, and the generated random number can be negative too, so
        long as the range (max - min + 1) is less than or equal to 32767. Max must be >= min.

This file is part of eRCaGuy_dotfiles: https://github.com/ElectricRCAircraftGuy/eRCaGuy_dotfiles
"

print_help() {
    echo "$HELP_STR" | less -RFX
}

# Get a random number according to the usage styles above.
# See also `utils_rand()` in utilities.c:
# https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/c/utilities.c#L176
random() {
    # PARSE ARGUMENTS

    # help menu
    if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
        print_help
        exit $RETURN_CODE_SUCCESS
    fi

    # 'random'
    if [ $# -eq 0 ]; then
        min=0
        max="none"
    # 'random max'
    elif [ $# -eq 1 ]; then
        min=0
        max="$1"
    # 'random min max'
    elif [ $# -eq 2 ]; then
        min="$1"
        max="$2"
    else
        echo "ERROR: too many arguments."
        exit "$RETURN_CODE_ERROR"
    fi

    # CHECK FOR ERRORS

    if [ "$max" = "none" ]; then
        rand="$RANDOM"
        echo "$rand"
        exit "$RETURN_CODE_SUCCESS"
    fi

    if [ "$max" -lt "$min" ]; then
        echo "ERROR: max ($max) < min ($min). Max must be >= min."
        exit "$RETURN_CODE_ERROR"
    fi

    # CALCULATE THE RANDOM NUMBER

    # See `man bash` and search for `RANDOM`. This is a limitation of that value.
    RAND_MAX=32767

    range=$((max - min + 1))
    if [ "$range" -gt "$RAND_MAX" ]; then
        echo "ERROR: the range (max - min + 1) is too large. Max allowed = $RAND_MAX, but actual" \
             "range = ($max - $min + 1) = $range."
        exit "$RETURN_CODE_ERROR"
    fi

    # NB: `RANDOM` is a bash built-in variable. See `man bash`, and also here:
    # https://stackoverflow.com/a/1195035/4561887
    rand=$((min + (RANDOM % range)))
    echo "$rand"
}

# Set the global variable `run` to "true" if the script is being **executed** (not sourced) and
# `main` should run, and set `run` to "false" otherwise. One might source this script but intend
# NOT to run it if they wanted to import functions from the script.
# See:
# 1. *****https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/bash/argument_parsing__3_advanced__gen_prog_template.sh
# 1. my answer: https://stackoverflow.com/a/70662049/4561887
# 1. https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/bash/check_if_sourced_or_executed.sh
run_check() {
    # This is akin to `if __name__ == "__main__":` in Python.
    if [ "${FUNCNAME[-1]}" == "main" ]; then
        # This script is being EXECUTED, not sourced
        run="true"
    fi
}

# ----------------------------------------------------------------------------------------------------------------------
# Main program entry point
# ----------------------------------------------------------------------------------------------------------------------

# Only run main function if this file is being executed, NOT sourced.
run="false"
run_check
if [ "$run" == "true" ]; then
    random "$@"
fi

3voto

Euphoria Punkte 41

Basierend auf den großartigen Antworten von @Nelson, @Barun und @Robert, hier ist ein Bash-Skript, das Zufallszahlen generiert.

  • Sie können so viele Ziffern erzeugen, wie Sie möchten.
  • jede Ziffer wird separat erzeugt durch /dev/urandom que es viel besser als die in der Bash eingebaute $RANDOM

    !/usr/bin/env bash

    digits=10

    rand=$(od -A n -t d -N 2 /dev/urandom |tr -d ' ') num=$((rand % 10)) while [ ${#num} -lt $digits ]; do rand=$(od -A n -t d -N 1 /dev/urandom |tr -d ' ') num="${num}$((rand % 10))" done echo $num

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X