Wie generiert man in der Bash eine Zufallszahl innerhalb eines Bereichs?
Antworten
Zu viele Anzeigen?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
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
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
amax
, einschließlich. Beidemin
ymax
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 als32767
. 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:
- https://en.cppreference.com/w/c/numeric/random/rand
- 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
y32767
erzeugt wird. Die Folge von Zufallszahlen kann initialisiert werden, indem ein Wert zugewiesen wirdRANDOM
. WennRANDOM
esunset
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
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