Necesito generar un número de puerto aleatorio entre 2000-65000
un script de shell. El problema es$RANDOM
es un número de 15 bits, ¡así que estoy atascado!
PORT=$(($RANDOM%63000+2001))
funcionaría bien si no fuera por la limitación de tamaño.
¿Alguien tiene un ejemplo de cómo puedo hacer esto, tal vez extrayendo algo /dev/urandom
y poniéndolo dentro de un rango?
shuf
es relativamente reciente: lo he visto en los sistemas Ubuntu en los últimos dos años, pero no en el RHEL / CentOS actual.shuf
que en realidad permuta toda la entrada. Esto lo convierte en una mala elección si está generando números aleatorios con mucha frecuencia.time for i in {1..1000}; do shuf -i 0-$end -n 1000 > /dev/null; done
y comparandoend=1
aend=65535
mostró aproximadamente una mejora del 25% para la gama más corta que ascendió a aproximadamente 4 segundos diferencia más de un millón iteraciones. Y es mucho más rápido que realizar el cálculo de Bash del OP un millón de veces.-n 1
mostró diferencias de tiempo insignificantes, incluso conend=4000000000
. Es bueno saber queshuf
funciona de manera inteligente, no difícil :-)En Mac OS X y FreeBSD también puede usar jot:
fuente
jot
tiene una distribución injusta para el mínimo y el máximo del intervalo (es decir, 2000 y 65000). En otras palabras, el mínimo y el máximo se generarán con menos frecuencia. Vea mi respuesta jota para más detalles y una solución alternativa.jot
también está disponible en la mayoría de las distribuciones de GNU / LinuxSegún la página de manual de bash,
$RANDOM
se distribuye entre 0 y 32767; es decir, es un valor de 15 bits sin signo. Suponiendo que$RANDOM
se distribuye uniformemente, puede crear un entero de 30 bits sin signo distribuido uniformemente de la siguiente manera:Debido a que su rango no es una potencia de 2, un simple operación de módulo sólo será casi le dan una distribución uniforme, pero con un rango de entrada de 30 bits y un rango de salida de menos-que-16 bits, ya que tiene en su caso, esto realmente debería estar lo suficientemente cerca:
fuente
$RANDOM
no siempre está disponible en todos los shells. Buscando otra solución$RANDOM
dos veces. En los shells que admiten$RANDOM
, se genera un nuevo valor cada vez que se hace referencia a él. Entonces, este código llena los bits 0 a 14 con un$RANDOM
valor y los bits 15 a 29 con otro. Suponiendo que$RANDOM
sea uniforme e independiente, esto cubre todos los valores de 0 a 2 ** 30-1 sin omitir nada.y aquí hay uno con Python
y uno con awk
fuente
RANDOM
POSIX no lo garantiza,-S
opción da como resultadoImportError: No module named random
. Funciona si elimino eso. No estoy seguro de cuál era la intención de ghostdog para eso.python -S -c "import random; print random.randrange(2000,63000)"
Parece funcionar bien. Sin embargo, cuando trato de obtener un número aleatorio entre 1 y 2, parece que siempre obtengo 1 ... ¿Pensamientos?La forma general más simple que me viene a la mente es una línea perl:
Siempre puedes usar dos números:
Todavía tiene que recortar a su rango. No es un método general de números aleatorios de n bits, pero funcionará para su caso, y todo está dentro de bash.
Si quieres ser realmente lindo y leer desde / dev / urandom, puedes hacer esto:
Eso leerá dos bytes y los imprimirá como un int sin signo; todavía tienes que hacer tu recorte.
fuente
awk
Si no eres un experto en bash y estabas buscando convertir esto en una variable en un script bash basado en Linux, prueba esto:
VAR=$(shuf -i 200-700 -n 1)
Eso te da el rango de 200 a 700
$VAR
, inclusive.fuente
Aqui hay otro más. Pensé que funcionaría en casi cualquier cosa, pero la opción aleatoria de ordenar no está disponible en mi caja de centos en el trabajo.
fuente
sort -R
tampoco está disponible en OS X.$RANDOM
es un número entre 0 y 32767. Desea un puerto entre 2000 y 65000. Estos son 63001 puertos posibles. Si nos atenemos a valores$RANDOM + 2000
entre 2000 y 33500 , cubrimos un rango de 31501 puertos. Si lanzamos una moneda y luego agregamos condicionalmente 31501 al resultado, podemos obtener más puertos, de 33501 a 65001 . Entonces, si simplemente dejamos caer 65001, obtenemos la cobertura exacta necesaria, con una distribución de probabilidad uniforme para todos los puertos, parece.Pruebas
fuente
Puedes hacerlo
Si necesita más detalles, consulte Shell Script Random Number Generator .
fuente
Lo mismo con el rubí:
fuente
La documentación de Bash dice que cada vez
$RANDOM
se hace referencia, se devuelve un número aleatorio entre 0 y 32767. Si sumamos dos referencias consecutivas, obtenemos valores de 0 a 65534, que cubren el rango deseado de 63001 posibilidades para un número aleatorio entre 2000 y 65000.Para ajustarlo al rango exacto, utilizamos el módulo de suma 63001, que nos dará un valor de 0 a 63000. Esto a su vez solo necesita un incremento en 2000 para proporcionar el número aleatorio deseado, entre 2000 y 65000. Esto puede ser resumido de la siguiente manera:
Pruebas
Corrección del cálculo.
Aquí hay una prueba completa de fuerza bruta para la exactitud del cálculo. Este programa solo intenta generar todas las 63001 posibilidades diferentes al azar, utilizando el cálculo bajo prueba. El
--jobs
parámetro debería hacer que se ejecute más rápido, pero no es determinista (el total de posibilidades generadas puede ser inferior a 63001).Para determinar cuántas iteraciones se necesitan para obtener una probabilidad dada
p/q
de que se hayan generado todas las posibilidades de 63001, creo que podemos usar la expresión a continuación. Por ejemplo, aquí está el cálculo para una probabilidad mayor que 1/2 , y aquí para mayor que 9/10 .fuente
$RANDOM
es un número entero . Con su "truco" hay muchos valores que nunca se alcanzarán.-1
.$RANDOM
, y no refactorizar eso en una multiplicación por dos, ya que$RANDOM
se supone que cambia en cada acceso. He actualizado la respuesta con la versión de suma.RANDOM+RANDOM
no te dará una distribución uniforme de números aleatorios entre 0 y 65534.O en OS-X, lo siguiente funciona para mí:
fuente
PORT=$(($RANDOM%63000+2001))
está cerca de lo que quieres, creo.PORT=$(($RANDOM$RANDOM$RANDOM%63000+2001))
evita la limitación de tamaño que te preocupa. Como bash no hace distinciones entre una variable numérica y una variable de cadena, esto funciona perfectamente bien. El "número"$RANDOM
puede concatenarse como una cadena, y luego usarse como un número en un cálculo. ¡Asombroso!fuente
x=$(( $n%63000 )
es más o menos similar ax=$(( $n % 65535 )); if [ $x -gt 63000 ]; then x=63000
.Puede obtener el número aleatorio a través de
urandom
head -200 /dev/urandom | cksum
Salida:
3310670062 52870
Para recuperar la parte del número anterior.
head -200 /dev/urandom | cksum | cut -f1 -d " "
Entonces la salida es
3310670062
Para cumplir con sus requisitos,
head -200 /dev/urandom |cksum | cut -f1 -d " " | awk '{print $1%63000+2001}'
fuente
Así es como generalmente genero números aleatorios. Luego uso "NUM_1" como la variable para el número de puerto que uso. Aquí hay un breve script de ejemplo.
fuente