Risposte:
Usa $RANDOM
. È spesso utile in combinazione con l'aritmetica semplice della shell. Ad esempio, per generare un numero casuale compreso tra 1 e 10 (incluso):
$ echo $((1 + RANDOM % 10))
3
Il generatore attuale è nella variables.c
funzione brand()
. Le versioni precedenti erano un semplice generatore lineare. La versione 4.0 bash
utilizza un generatore che cita un documento del 1985, il che presumibilmente significa che è una discreta fonte di numeri pseudocasuali. Non lo userei per una simulazione (e certamente non per la crittografia), ma è probabilmente adeguato per le attività di scripting di base.
Se stai facendo qualcosa che richiede numeri casuali seri che puoi usare /dev/random
o /dev/urandom
se sono disponibili:
$ dd if=/dev/urandom count=4 bs=1 | od -t d
$RANDOM % 10
, 8 e 9 sono misurabili (anche se marginalmente) meno probabili di 0-7, anche se $RANDOM
è una solida fonte di dati casuali.
$RANDOM
gamma 's è 0-32767
il numero 0
- 7
mappare 3277
diversi ingressi possibili, ma 8
e 9
può essere prodotto solo 3276
modi diversi (perché 32768
e 32769
non sono possibili). Questo è un problema minore per gli hack rapidi, ma significa che il risultato non è uniformemente casuale. Le librerie casuali, come quelle di Java Random
, offrono funzioni per restituire correttamente un numero casuale uniforme in un determinato intervallo, anziché semplicemente modificare un numero non divisibile.
Si prega di vedere $RANDOM
:
$RANDOM
è una funzione Bash interna (non una costante) che restituisce un numero intero pseudocasuale nell'intervallo 0 - 32767. Non deve essere utilizzato per generare una chiave di crittografia.
32767
ha alcun significato particolare?
32767
è 2^16 / 2 - 1
il limite superiore per un numero intero a 16 bit con segno.
2^15 - 1
? È equivalente, quindi sono solo curioso di sapere se c'è qualche contesto che mi manca?
Puoi anche usare shuf (disponibile in coreutils).
shuf -i 1-100000 -n 1
shuf -i 1-10 -n 1: syntax error in expression (error token is "1-10 -n 1")
$var
di fine gamma, in questo modo:var=100 && shuf -i 1-${var} -n 1
-n
. Ad esempio, genera 5 numeri casuali tra 1 e 100 :shuf -i 1-100 -n 5
shuf -i 1-10 -n 10
otterrai tutti i numeri da 1 a 10 esattamente uno. Se specifichi -n 15
otterrai comunque solo quei 10 numeri esattamente una volta. Questo è davvero solo mescolare, non generare numeri casuali.
Prova questo dalla tua shell:
$ od -A n -t d -N 1 /dev/urandom
Qui, -t d
specifica che il formato di output deve essere decimale; -N 1
dice di leggere un byte da /dev/urandom
.
od -A n -t d -N 1 /dev/urandom |tr -d ' '
puoi anche ottenere un numero casuale da awk
awk 'BEGIN {
# seed
srand()
for (i=1;i<=1000;i++){
print int(1 + rand() * 100)
}
}'
srand()
il seme è il tempo corrente della CPU. Se è necessario specificare un seme specifico, in modo da poter duplicare RNG, utilizzare srand(x)
dove si x
trova il seme. Inoltre, citato dal manuale di funzioni numeriche di GNU awk, "diverse implementazioni di awk usano internamente diversi generatori di numeri casuali". Il risultato è che se sei interessato a generare una distribuzione statistica, dovresti aspettarti lievi variazioni che vanno da un runtime al successivo su piattaforme diverse (tutte in esecuzione awk
o gawk
).
C'è $ RANDOM. Non so esattamente come funzioni. Ma funziona Per i test, puoi fare:
echo $RANDOM
Mi piace questo trucco:
echo ${RANDOM:0:1} # random number between 1 and 9
echo ${RANDOM:0:2} # random number between 1 and 99
...
${RANDOM:0:1}
ha una probabilità del 67,8% di darti un 1 o un 2, ${RANDOM:0:2}
ha solo una probabilità dello 0,03% di darti un numero a una cifra (dovrebbe essere dell'1%) ed entrambi hanno una probabilità dello 0,003% di darti uno 0 Vi sono ancora casi d'uso in cui ciò va bene (ad esempio input non coerente).
Numero casuale compreso tra 0 e 9 inclusi.
echo $((RANDOM%10))
$RANDOM
va solo da 0 a 32767. Avrebbe dovuto dire "Numero casuale principalmente tra 1 e 3, con poche ali";)
Se stai usando un sistema Linux puoi ottenere un numero casuale da / dev / random o / dev / urandom. Fai attenzione / dev / random bloccherà se non ci sono abbastanza numeri casuali disponibili. Se hai bisogno di velocità sulla casualità usa / dev / urandom.
Questi "file" saranno riempiti con numeri casuali generati dal sistema operativo. Dipende dall'implementazione di / dev / random sul tuo sistema se ottieni numeri veri o pseudo casuali. I veri numeri casuali vengono generati con l'aiuto del rumore raccolto dai driver di dispositivo come mouse, disco rigido, rete.
È possibile ottenere numeri casuali dal file con dd
Ho preso alcune di queste idee e creato una funzione che dovrebbe svolgere rapidamente se sono richiesti molti numeri casuali.
chiamare od
è costoso se hai bisogno di molti numeri casuali. Invece lo chiamo una volta e memorizzo 1024 numeri casuali da / dev / urandom. quandorand
viene chiamato, l'ultimo numero casuale viene restituito e ridimensionato. Viene quindi rimosso dalla cache. Quando la cache è vuota, vengono letti altri 1024 numeri casuali.
Esempio:
rand 10; echo $RET
Restituisce un numero casuale in RET tra 0 e 9 inclusi.
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
AGGIORNAMENTO: Questo non funziona così bene per tutti N. Inoltre spreca bit casuali se usato con N. piccolo Notando che (in questo caso) un numero casuale a 32 bit ha abbastanza entropia per 9 numeri casuali tra 0 e 9 (10 * 9 = 1.000.000.000 <= 2 * 32) possiamo estrarre più numeri casuali da ciascun valore di 32 fonti casuali.
#!/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
od -An -tu4 -N40 /dev/urandom
genererà 10 numeri interi a 32 bit senza segno casuali separati da spazi bianchi. puoi memorizzarlo in un array e usarlo in seguito. il tuo codice sembra essere eccessivo.
La lettura da file speciali / dev / random o / dev / urandom è la strada da percorrere.
Questi dispositivi restituiscono numeri veramente casuali quando vengono letti e sono progettati per aiutare il software applicativo a scegliere chiavi sicure per la crittografia. Tali numeri casuali sono estratti da un pool di entropia che è contribuito da vari eventi casuali. {LDD3, Jonathan Corbet, Alessandro Rubini e Greg Kroah-Hartman]
Questi due file sono l'interfaccia per la randomizzazione del kernel, in particolare
void get_random_bytes_arch(void* buf, int nbytes)
che disegna byte veramente casuali dall'hardware se tale funzione è implementata dall'hardware (di solito lo è) o attinge dal pool di entropia (composto da temporizzazioni tra eventi come interruzioni del mouse e della tastiera e altri interruzioni registrate con SA_SAMPLE_RANDOM).
dd if=/dev/urandom count=4 bs=1 | od -t d
Funziona, ma scrive l'output non necessario da dd
stdout. Il comando seguente fornisce solo l'intero di cui ho bisogno. Posso persino ottenere il numero specificato di bit casuali di cui ho bisogno regolando la maschera di bit data all'espansione aritmetica:
me@mymachine:~/$ x=$(head -c 1 /dev/urandom > tmp && hexdump
-d tmp | head -n 1 | cut -c13-15) && echo $(( 10#$x & 127 ))
Forse sono un po 'troppo tardi, ma che ne dici di usare jot
per generare un numero casuale all'interno di un intervallo in Bash?
jot -r -p 3 1 0 1
Questo genera un -r
numero casuale ( ) con 3 decimali di precisione ( -p
). In questo caso particolare, otterrai un numero compreso tra 0 e 1 ( 1 0 1
). È inoltre possibile stampare dati sequenziali. La fonte del numero casuale, secondo il manuale, è:
I numeri casuali sono ottenuti attraverso arc4random (3) quando non viene specificato alcun seme e attraverso random (3) quando viene dato un seme.
Basato sulle grandi risposte di @Nelson, @Barun e @Robert, ecco uno script Bash che genera numeri casuali.
/dev/urandom
che è molto meglio di quello incorporato di Bash$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
Genera un numero casuale nell'intervallo da 0 a n (numero intero a 16 bit con segno). Risultato impostato nella variabile $ RAND. Per esempio:
#!/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
Diramazione casuale di un programma o sì / no; 1/0; output vero / falso:
if [ $RANDOM -gt 16383 ]; then # 16383 = 32767/2
echo var=true/1/yes/go_hither
else
echo var=false/0/no/go_thither
fi
di se sei pigro da ricordare 16383:
if (( RANDOM % 2 )); then
echo "yes"
else
echo "no"
fi