2009-07-28 54 views

Respuesta

47

favor ver $RANDOM:

$RANDOM es una función interna Bash (no una constante) que devuelve un número entero pseudoaleatorio en el intervalo 0 - 32767. No se debe utilizar para generar un cifrado llave.

+0

¿Tiene '32767' algún significado especial? –

+4

@JinKwon '32767' es' 2^16/2 - 1' que es el límite superior para un entero de 16 bits con signo. –

13

Hay $ RANDOM. No sé exactamente cómo funciona. Pero funciona. Para la prueba, que puede hacer:

echo $RANDOM 
5

Si está utilizando un sistema Linux se puede obtener un número aleatorio de /dev/random or/dev/urandom. Tenga cuidado/dev/random bloqueará si no hay suficientes números aleatorios disponibles. Si necesita velocidad sobre la aleatoriedad, use/dev/urandom.

Estos "archivos" se llenarán con números aleatorios generados por el sistema operativo. Depende de la implementación de/dev/random en su sistema si obtiene números verdaderos o pseudoaleatorios. Los verdaderos números aleatorios se generan con la ayuda del ruido generado por los controladores del dispositivo, como el mouse, el disco duro o la red.

Puede obtener números aleatorios desde el archivo con dd

135

Uso $RANDOM. A menudo es útil en combinación con la simple aritmética de shell. Por ejemplo, para generar un número aleatorio entre 1 y 10:

$ echo $((1 + RANDOM % 10)) 
3 

El generador real es en variables.c, la función brand(). Older versions eran un generador lineal simple. La versión 4.0 de bash usa un generator with a citation en un documento de 1985, lo que presumiblemente significa que es una fuente decente de números pseudoaleatorios. No lo usaría para una simulación (y ciertamente no para criptografía), pero probablemente sea adecuado para tareas básicas de scripting.

Si estás haciendo algo que requiere números aleatorios graves puede utilizar /dev/random/dev/urandom o si están disponibles:

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

Ten cuidado aquí. Si bien esto está bien en un apuro, hacer aritmética en números aleatorios puede afectar dramáticamente la aleatoriedad de su resultado. en el caso de '$ RANDOM% 10', 8 y 9 son mensurablemente (aunque marginalmente) menos probables que 0-7, incluso si' $ RANDOM' es una fuente robusta de datos aleatorios. – dimo414

+2

@ dimo414 Tengo curiosidad por saber "marginalmente", ¿tiene alguna fuente donde pueda obtener más información al respecto? – PascalVKooten

+17

Modulando su entrada aleatoria, usted es "[pigeon-holing] (http://en.wikipedia.org/wiki/Pigeonhole_principle)" los resultados. Como el rango '$ RANDOM' es' 0-32767' los números '0'-'7' se mapean a' 3277' diferentes entradas posibles, pero '8' y' 9' solo pueden ser '3276' (porque '32768' y' 32769' no son posibles). Este es un problema menor para hacks rápidos, pero significa que el resultado no es uniformemente aleatorio. Las bibliotecas aleatorias, como '' Random'' de Java, ofrecen funciones para devolver correctamente un número aleatorio uniforme en el rango dado, en lugar de simplemente modificar un número no divisible. – dimo414

14

también se puede obtener números aleatorios desde awk

awk 'BEGIN { 
    # seed 
    srand() 
    for (i=1;i<=1000;i++){ 
    print int(1 + rand() * 100) 
    } 
}' 
+1

+1 ya sabes, al principio pensé por qué querrías hacerlo así, pero en realidad me gusta bastante. – zelanix

+1

Gracias por dar una solución que incluye la siembra. ¡No pude encontrarlo en ningún lado! –

24

Try esto desde su caparazón:

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

Aquí, -t d especifica que el formato de salida debe ser un decimal con signo; -N 1 dice leer un byte desde /dev/urandom.

+1

La pregunta pide números en un rango. – NBCKLY

+4

puede eliminar espacios: 'od -A n -t d -N 1/dev/urandom | tr -d ''' – Robert

0

Genera un número aleatorio en el rango de 0 a n (entero de 16 bits con signo). Resultado establecido en la variable $ RAND. Por ejemplo:

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

Número aleatorio entre 0 y 9 inclusive.

echo $((RANDOM%10)) 
+1

Malo, no leí la página del manual correctamente. '$ RANDOM' solo va de 0 a 32767. Debería haber dicho" Número aleatorio mayormente entre 1 y 3, con algunos extremos ";) –

+0

¿Qué? Todavía estará entre 0 y 9, aunque 8 y 9 tendrán una probabilidad ligeramente menor de ocurrir que 0 a 7, como se menciona en otra respuesta. – kini

3

He tomado algunas de estas ideas e hice una función que debería funcionar rápidamente si se requieren muchos números aleatorios.

llamando al od es costoso si necesita muchos números aleatorios. En cambio, lo llamo una vez y almaceno 1024 números aleatorios de/dev/urandom. Cuando se llama al rand, se devuelve y modifica el último número aleatorio. Luego se elimina de la memoria caché. Cuando la memoria caché está vacía, se leen otros 1024 números aleatorios.

Ejemplo:

rand 10; echo $RET 

devuelve un número aleatorio en RET entre 0 y 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 

ACTUALIZACIÓN: Eso no funciona tan bien para todos N. También desperdicia bits aleatorios si se utiliza con un pequeño N. Tomando nota de que (en este caso) un número aleatorio de 32 bits tiene suficiente entropía para 9 números aleatorios entre 0 y 9 (10 * 9 = 1,000,000,000 < = 2 * 32) podemos extraer múltiples números aleatorios de cada 32 valores fuente aleatorios.

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

Intenté esto: tomó 10 segundos de 100% de CPU y luego imprimí 10 números que no parecían aleatorios en TODOS. –

+0

Recuerdo ahora. Este código genera 100,000 números aleatorios. Pone cada uno en un "contenedor" para ver qué tan aleatorio es. Hay 10 contenedores. Estos números deberían ser similares si cada número aleatorio entre 0 y 9 es igualmente probable. Si desea imprimir cada número, echo $ RET después de randBetween 10. – philcolbourn

+0

'od -An -tu4 -N40/dev/urandom' generará 10 enteros aleatorios sin signo de 32 bits separados con espacios en blanco. puedes almacenarlo en una matriz y usarlo luego. tu código parece ser un exceso. – Ali

0

¿Qué hay de:

perl -e 'print int rand 10, "\n"; ' 
2

lectura desde/archivos especiales dev/random o/dev caracteres/urandom es el camino a seguir.

Estos dispositivos devuelven números verdaderamente aleatorios cuando se leen y están diseñados para ayudar al software de aplicación a elegir claves seguras para el cifrado. Dichos números aleatorios se extraen de un conjunto de entropía que se contribuye por varios eventos aleatorios. {LDD3, Jonathan Corbet, Alessandro Rubini, y Greg Kroah-Hartman]

Estos dos archivos son la interfaz del núcleo en la aleatorización, en particular,

void get_random_bytes_arch(void* buf, int nbytes) 

que atrae bytes verdaderamente aleatorios de hardware si dicha función es por hardware implementado (normalmente lo es), o se basa en un conjunto de entropía (compuesto por tiempos entre eventos como interrupciones de mouse y teclado y otras interrupciones registradas con SA_SAMPLE_RANDOM).

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

Esto funciona, pero escribe salida innecesaria de dd a la salida estándar. El siguiente comando da solo el número entero que necesito. Incluso puedo obtener el número de bits aleatorios especificada, ya que necesito por el ajuste de la máscara de bits dado a expansión aritmética:

[email protected]:~/$ x=$(head -c 1 /dev/urandom > tmp && hexdump 
         -d tmp | head -n 1 | cut -c13-15) && echo $((10#$x & 127)) 
+1

@gniourf_gniourf arreglado, gracias – 4pie0

7

También puede utilizar shuf (disponible en coreutils).

shuf -i 1-100000 -n 1 
1

Me gusta este truco:

echo ${RANDOM:0:1} # random number between 1 and 9 
echo ${RANDOM:0:2} # random number between 1 and 99 

...

Cuestiones relacionadas