Uso $RANDOM. A menudo es útil en combinación con aritmética de shell simple. Por ejemplo, para generar un número aleatorio entre 1 y 10 (inclusive):
$ echo $((1+ RANDOM %10))3
El generador real está en variables.c, la función brand(). Las versiones anteriores eran un generador lineal simple. La versión 4.0 de bashutiliza un generador con una cita de un artículo 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 secuencias de comandos.
Si está haciendo algo que requiere números aleatorios serios que puede usar /dev/randomo /dev/urandomsi están disponibles:
Ten cuidado aquí. Si bien esto está bien en caso de apuro, hacer aritmética en números aleatorios puede afectar dramáticamente la aleatoriedad de su resultado. en el caso de $RANDOM % 108 y 9 son mensurables (aunque marginalmente) menos probables que 0-7, incluso si $RANDOMes una fuente sólida de datos aleatorios.
dimo414
3
@ dimo414 Tengo curiosidad por "marginalmente", ¿tiene una fuente donde pueda obtener más información al respecto?
PascalVKooten
58
Al modular su entrada aleatoria, está "haciendo palomas " los resultados. Dado que $RANDOMel rango son 0-32767los números 0, se 7asignan a 3277diferentes entradas posibles, pero 8y 9solo se pueden producir de 3276diferentes maneras (porque 32768y 32769no son posibles). Este es un problema menor para los hacks rápidos, pero significa que el resultado no es uniforme al azar. Las bibliotecas aleatorias, como las de Java Random, ofrecen funciones para devolver adecuadamente un número aleatorio uniforme en el rango dado, en lugar de simplemente modificar un número no divisible.
dimo414
1
@JFSebastian muy cierto: el problema con el módulo es que puede romper la uniformidad de cualquier RNG, no solo los PRNG malos, sino que gracias por llamarlo.
dimo414
14
Solo por contexto, el encasillamiento básico para% 10 significa que 8 y 9 tienen aproximadamente 0.03% menos probabilidades de ocurrir que 0–7. Si su script de shell requiere números aleatorios uniformes más precisos que eso, entonces, por supuesto, use un mecanismo más complejo y adecuado.
$RANDOM es una función Bash interna (no una constante) que devuelve un entero pseudoaleatorio en el rango de 0 a 32767. No debe usarse para generar una clave de cifrado.
@JinKwon 32767es 2^16 / 2 - 1cuál es el límite superior para un entero de 16 bits con signo.
Jeffrey Martinez
@ JinKwon, ¿podría aclarar por qué no dice que es así 2^15 - 1? Es equivalente, así que tengo curiosidad si hay algún contexto que me falta.
Brett Holman el
11
@BrettHolman Creo que estaba tratando de señalar la parte "firmada" del entero de 16 bits firmado. 2 ^ 16 valores, divididos por la mitad para entradas positivas y negativas.
cody
Esta respuesta no responde la pregunta.
mocoso
48
También puede usar shuf (disponible en coreutils).
¿Cómo pasas en vars como final de rango? Tengo esto:shuf -i 1-10 -n 1: syntax error in expression (error token is "1-10 -n 1")
dat tutbrus
1
Agregue un en $varlugar del final del rango, como este:var=100 && shuf -i 1-${var} -n 1
knipwim
2
Prefiero esta opción, ya que es fácil generar N números aleatorios con -n. Por ejemplo, generar 5 números aleatorios entre 1 y 100 :shuf -i 1-100 -n 5
aerijman
Hasta donde yo entiendo, los números no son aleatorios. Si lo especifica shuf -i 1-10 -n 10, obtendrá todos los números del 1 al 10 exactamente uno. Si especificas -n 15, obtendrás solo esos 10 números exactamente una vez. Eso es realmente solo barajar, no generar números aleatorios.
Radlan
Para obtener números aleatorios con reemplazo: -r
Geoffrey Anderson
36
Prueba esto desde tu shell:
$ od -A n -t d -N 1/dev/urandom
Aquí, -t despecifica que el formato de salida debe ser con signo decimal; -N 1dice que lea un byte de /dev/urandom.
+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!
so.very
2
+1 para la siembra. Vale la pena mencionar que srand()la semilla es el tiempo de CPU actual. Si necesita especificar una semilla específica, para que RNG pueda duplicarse, use srand(x)where xis the seed. Además, citado del manual de funciones numéricas de GNU awk, "diferentes implementaciones de awk usan diferentes generadores de números aleatorios internamente". El resultado es que si está interesado en generar una distribución estadística, debe esperar ligeras variaciones de un tiempo de ejecución a otro en una plataforma diferente (todas en ejecución awko gawk).
Cbhihe
18
Hay $ RANDOM. No sé exactamente cómo funciona. Pero funciona. Para las pruebas, puede hacer:
$ RANDOM está en el rango de 0 - 32767. Terminará con más números que comienzan con 1, 2 o 3, que tendrá 4-9. Si está de acuerdo con una distribución desequilibrada, esto funcionará bien.
jbo5112
2
@ jbo5112 tiene toda la razón, ¿qué pasa con mostrar el último dígito? echo $ {RANDOM: 0-1} para un dígito, $ {RANDOM: 0-2} para dos dígitos ...?
fraff
44
Si utiliza los últimos dígitos, será bastante bueno, pero incluirá 0 y 00. En un solo dígito, 0-7 ocurrirá 0.03% más a menudo que 8-9. En 2 dígitos, 0-67 ocurrirá 0.3% más a menudo que 68-99. Si necesita una distribución aleatoria de números tan buena, espero que no esté usando bash. Con el original: ${RANDOM:0:1}tiene una probabilidad del 67.8% de darle un 1 o un 2, ${RANDOM:0:2}solo tiene una probabilidad del 0.03% de darle un número de un solo dígito (debe ser 1%), y ambos tienen una probabilidad del 0.003% de darle un 0 Todavía hay casos de uso en los que esto está bien (por ejemplo, entrada no coherente).
Lo malo, no leí la página del manual correctamente. $RANDOMsolo va de 0 a 32767. Debería haber dicho "Número aleatorio principalmente entre 1 y 3, con algunos extremos";)
David Newcomb
1
¿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
6
Si está utilizando un sistema Linux, puede obtener un número aleatorio de / dev / random o / dev / urandom. Tenga cuidado con / dev / random se bloqueará si no hay suficientes números aleatorios disponibles. Si necesita velocidad sobre 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. Se generan números aleatorios verdaderos con la ayuda del ruido acumulado de los controladores de dispositivos como el mouse, el disco duro y la red.
Puede obtener números aleatorios del archivo con dd
Tomé algunas de estas ideas e hice una función que debería funcionar rápidamente si se requieren muchos números aleatorios.
llamar odes costoso si necesita muchos números aleatorios. En cambio, lo llamo una vez y almaceno 1024 números aleatorios de / dev / urandom. Cuando randse llama, se devuelve el último número aleatorio y se escala. Luego se elimina del caché. Cuando el caché está vacío, 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^32local-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 distributiondonefor(( c=0; c<10; c++));do
printf "%d %d\n" $c ${BIN[c]}done
ACTUALIZACIÓN: Eso no funciona tan bien para todos los N. También desperdicia bits aleatorios si se usa con pequeños N. Observando 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 valor fuente aleatorio.
#!/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]+=1donefor c in ${BIN[*]};do
echo $c
done
Intenté esto: tomó 10 segundos de 100% de CPU y luego imprimí 10 números que no parecían aleatorios en absoluto.
Carlo Wood
Ahora recuerdo. Este código genera 100,000 números aleatorios. Pone a cada uno en un 'contenedor' para ver qué tan aleatorio es. Hay 10 contenedores. Estos números deben ser similares si cada número aleatorio entre 0 y 9 es igualmente probable. Si desea imprimir cada número, repita $ RET después de randEntre 10.
philcolbourn
od -An -tu4 -N40 /dev/urandomgenerará 10 enteros aleatorios de 32 bits sin signo separados con espacios en blanco. puede almacenarlo en una matriz y usarlo después. Su código parece ser una exageración.
Ali
@ Ali, OP no especificó que querían 32 bits ni ningún otro número aleatorio de tamaño. Yo y algunos otros interpretamos esta pregunta como un número aleatorio dentro de un rango. Mi función rand logra este objetivo y también reduce la pérdida de entropía que, si se agota, hace que los programas se bloqueen. od on / dev / urandom devuelve solo números aleatorios de 2 ^ N bits y OP necesitaría almacenar múltiples valores en una matriz, extraerlos secuencialmente de esta matriz y reponer esta matriz. ¿Quizás pueda codificar esto como respuesta y manejar otros rangos de números aleatorios?
philcolbourn
@philcolbourn, tienes razón acerca de que el OP no especifica qué tipo de número aleatorio quiere y me llamó la atención. Pero solo preguntó: "¿Cómo generar un número aleatorio en bash?". Mi punto es que solo pidió un número aleatorio. Aunque esta crítica se aplica a mi comentario anterior (que genera 10 números aleatorios) también.
Ali
5
Lectura de archivos especiales de caracteres / dev / random o / dev / 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. Tales números aleatorios se extraen de un grupo de entropía que es contribuido por varios eventos aleatorios. {LDD3, Jonathan Corbet, Alessandro Rubini y Greg Kroah-Hartman]
Estos dos archivos son interfaz para aleatorización del núcleo, en particular
void get_random_bytes_arch(void* buf, int nbytes)
que extrae bytes realmente aleatorios del hardware si dicha función es implementada por hardware (por lo general, es), o extrae del grupo de entropía (compuesto de temporizaciones entre eventos como interrupciones del mouse y del teclado y otras interrupciones que están registradas con SA_SAMPLE_RANDOM).
dd if=/dev/urandom count=4 bs=1| od -t d
Esto funciona, pero escribe salidas innecesarias desde ddstdout. El siguiente comando da solo el número entero que necesito. Incluso puedo obtener el número especificado de bits aleatorios que necesito mediante el ajuste de la máscara de bits dada a la expansión aritmética:
Para obtener un número aleatorio criptográficamente seguro, debe leer / dev / urandom o usar las bibliotecas Crypt :: Random.
kh
3
Tal vez llego un poco tarde, pero ¿qué pasa con el uso jotpara generar un número aleatorio dentro de un rango en Bash?
jot -r -p 3101
Esto genera un número aleatorio ( -r) con 3 decimales de precisión ( -p). En este caso particular, obtendrá un número entre 0 y 1 ( 1 0 1). También puede imprimir datos secuenciales. La fuente del número aleatorio, según el manual, es:
Los números aleatorios se obtienen a través de arc4random (3) cuando no se especifica ninguna semilla, y a través de random (3) cuando se da una semilla.
Respuestas:
Uso
$RANDOM
. A menudo es útil en combinación con aritmética de shell simple. Por ejemplo, para generar un número aleatorio entre 1 y 10 (inclusive):El generador real está en
variables.c
, la funciónbrand()
. Las versiones anteriores eran un generador lineal simple. La versión 4.0 debash
utiliza un generador con una cita de un artículo 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 secuencias de comandos.Si está haciendo algo que requiere números aleatorios serios que puede usar
/dev/random
o/dev/urandom
si están disponibles:fuente
$RANDOM % 10
8 y 9 son mensurables (aunque marginalmente) menos probables que 0-7, incluso si$RANDOM
es una fuente sólida de datos aleatorios.$RANDOM
el rango son0-32767
los números0
, se7
asignan a3277
diferentes entradas posibles, pero8
y9
solo se pueden producir de3276
diferentes maneras (porque32768
y32769
no son posibles). Este es un problema menor para los hacks rápidos, pero significa que el resultado no es uniforme al azar. Las bibliotecas aleatorias, como las de JavaRandom
, ofrecen funciones para devolver adecuadamente un número aleatorio uniforme en el rango dado, en lugar de simplemente modificar un número no divisible.Por favor vea
$RANDOM
:fuente
32767
Tiene algún significado especial?32767
es2^16 / 2 - 1
cuál es el límite superior para un entero de 16 bits con signo.2^15 - 1
? Es equivalente, así que tengo curiosidad si hay algún contexto que me falta.También puede usar shuf (disponible en coreutils).
fuente
shuf -i 1-10 -n 1: syntax error in expression (error token is "1-10 -n 1")
$var
lugar del final del rango, como este:var=100 && shuf -i 1-${var} -n 1
-n
. Por ejemplo, generar 5 números aleatorios entre 1 y 100 :shuf -i 1-100 -n 5
shuf -i 1-10 -n 10
, obtendrá todos los números del 1 al 10 exactamente uno. Si especificas-n 15
, obtendrás solo esos 10 números exactamente una vez. Eso es realmente solo barajar, no generar números aleatorios.Prueba esto desde tu shell:
Aquí,
-t d
especifica que el formato de salida debe ser con signo decimal;-N 1
dice que lea un byte de/dev/urandom
.fuente
od -A n -t d -N 1 /dev/urandom |tr -d ' '
también puedes obtener un número aleatorio de awk
fuente
srand()
la semilla es el tiempo de CPU actual. Si necesita especificar una semilla específica, para que RNG pueda duplicarse, usesrand(x)
wherex
is the seed. Además, citado del manual de funciones numéricas de GNU awk, "diferentes implementaciones de awk usan diferentes generadores de números aleatorios internamente". El resultado es que si está interesado en generar una distribución estadística, debe esperar ligeras variaciones de un tiempo de ejecución a otro en una plataforma diferente (todas en ejecuciónawk
ogawk
).Hay $ RANDOM. No sé exactamente cómo funciona. Pero funciona. Para las pruebas, puede hacer:
fuente
Me gusta este truco:
...
fuente
${RANDOM:0:1}
tiene una probabilidad del 67.8% de darle un 1 o un 2,${RANDOM:0:2}
solo tiene una probabilidad del 0.03% de darle un número de un solo dígito (debe ser 1%), y ambos tienen una probabilidad del 0.003% de darle un 0 Todavía hay casos de uso en los que esto está bien (por ejemplo, entrada no coherente).Número aleatorio entre 0 y 9 inclusive.
fuente
$RANDOM
solo va de 0 a 32767. Debería haber dicho "Número aleatorio principalmente entre 1 y 3, con algunos extremos";)Si está utilizando un sistema Linux, puede obtener un número aleatorio de / dev / random o / dev / urandom. Tenga cuidado con / dev / random se bloqueará si no hay suficientes números aleatorios disponibles. Si necesita velocidad sobre 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. Se generan números aleatorios verdaderos con la ayuda del ruido acumulado de los controladores de dispositivos como el mouse, el disco duro y la red.
Puede obtener números aleatorios del archivo con dd
fuente
Tomé algunas de estas ideas e hice una función que debería funcionar rápidamente si se requieren muchos números aleatorios.
llamar
od
es costoso si necesita muchos números aleatorios. En cambio, lo llamo una vez y almaceno 1024 números aleatorios de / dev / urandom. Cuandorand
se llama, se devuelve el último número aleatorio y se escala. Luego se elimina del caché. Cuando el caché está vacío, se leen otros 1024 números aleatorios.Ejemplo:
Devuelve un número aleatorio en RET entre 0 y 9 inclusive.
ACTUALIZACIÓN: Eso no funciona tan bien para todos los N. También desperdicia bits aleatorios si se usa con pequeños N. Observando 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 valor fuente aleatorio.
fuente
od -An -tu4 -N40 /dev/urandom
generará 10 enteros aleatorios de 32 bits sin signo separados con espacios en blanco. puede almacenarlo en una matriz y usarlo después. Su código parece ser una exageración.Lectura de archivos especiales de caracteres / dev / random o / dev / urandom es el camino a seguir.
Estos dos archivos son interfaz para aleatorización del núcleo, en particular
que extrae bytes realmente aleatorios del hardware si dicha función es implementada por hardware (por lo general, es), o extrae del grupo de entropía (compuesto de temporizaciones entre eventos como interrupciones del mouse y del teclado y otras interrupciones que están registradas con SA_SAMPLE_RANDOM).
Esto funciona, pero escribe salidas innecesarias desde
dd
stdout. El siguiente comando da solo el número entero que necesito. Incluso puedo obtener el número especificado de bits aleatorios que necesito mediante el ajuste de la máscara de bits dada a la expansión aritmética:fuente
Qué pasa:
fuente
Tal vez llego un poco tarde, pero ¿qué pasa con el uso
jot
para generar un número aleatorio dentro de un rango en Bash?Esto genera un número aleatorio (
-r
) con 3 decimales de precisión (-p
). En este caso particular, obtendrá un número entre 0 y 1 (1 0 1
). También puede imprimir datos secuenciales. La fuente del número aleatorio, según el manual, es:fuente
Basado en las excelentes respuestas de @Nelson, @Barun y @Robert, aquí hay un script Bash que genera números aleatorios.
/dev/urandom
cual es mucho mejor que el incorporado de Bash$RANDOM
fuente
Genere un número aleatorio en el rango de 0 a n (entero de 16 bits con signo). Conjunto de resultados en $ RAND variable. Por ejemplo:
fuente
Ramificación aleatoria de un programa o sí / no; 1/0; salida verdadero / falso:
de si eres perezoso para recordar 16383:
fuente