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.