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:
port=$((((RANDOM + RANDOM) % 63001) + 2000))
Pruebas
# Generate random numbers and print the lowest and greatest found
test-random-max-min() {
max=2000
min=65000
for i in {1..10000}; do
port=$((((RANDOM + RANDOM) % 63001) + 2000))
echo -en "\r$port"
[[ "$port" -gt "$max" ]] && max="$port"
[[ "$port" -lt "$min" ]] && min="$port"
done
echo -e "\rMax: $max, min: $min"
}
# Sample output
# Max: 64990, min: 2002
# Max: 65000, min: 2004
# Max: 64970, min: 2000
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).
test-all() {
start=$(date +%s)
find_start=$(date +%s)
total=0; ports=(); i=0
rm -f ports/ports.* ports.*
mkdir -p ports
while [[ "$total" -lt "$2" && "$all_found" != "yes" ]]; do
port=$((((RANDOM + RANDOM) % 63001) + 2000)); i=$((i+1))
if [[ -z "${ports[port]}" ]]; then
ports["$port"]="$port"
total=$((total + 1))
if [[ $((total % 1000)) == 0 ]]; then
echo -en "Elapsed time: $(($(date +%s) - find_start))s \t"
echo -e "Found: $port \t\t Total: $total\tIteration: $i"
find_start=$(date +%s)
fi
fi
done
all_found="yes"
echo "Job $1 finished after $i iterations in $(($(date +%s) - start))s."
out="ports.$1.txt"
[[ "$1" != "0" ]] && out="ports/$out"
echo "${ports[@]}" > "$out"
}
say-total() {
generated_ports=$(cat "$@" | tr ' ' '\n' | \sed -E s/'^([0-9]{4})$'/'0\1'/)
echo "Total generated: $(echo "$generated_ports" | sort | uniq | wc -l)."
}
total-single() { say-total "ports.0.txt"; }
total-jobs() { say-total "ports/"*; }
all_found="no"
[[ "$1" != "--jobs" ]] && test-all 0 63001 && total-single && exit
for i in {1..1000}; do test-all "$i" 40000 & sleep 1; done && wait && total-jobs
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 .

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 :-)