La documentation de Bash indique que chaque fois qu'il $RANDOM
est référencé, un nombre aléatoire compris entre 0 et 32767 est renvoyé. Si nous additionnons deux références consécutives, nous obtenons des valeurs de 0 à 65534, ce qui couvre la plage souhaitée de 63001 possibilités pour un nombre aléatoire entre 2000 et 65000.
Pour l'ajuster à la plage exacte, nous utilisons la somme modulo 63001, qui nous donnera une valeur de 0 à 63000. Cela à son tour a juste besoin d'un incrément de 2000 pour fournir le nombre aléatoire souhaité, entre 2000 et 65000. Cela peut être résumées comme suit:
port=$((((RANDOM + RANDOM) % 63001) + 2000))
Essai
# 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
Exactitude du calcul
Voici un test complet de force brute pour l'exactitude du calcul. Ce programme essaie simplement de générer toutes les 63001 possibilités différentes au hasard, en utilisant le calcul sous test. Le --jobs
paramètre devrait le faire fonctionner plus rapidement, mais il n'est pas déterministe (le total des possibilités générées peut être inférieur à 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
Pour déterminer combien d'itérations sont nécessaires pour obtenir une probabilité donnée que p/q
toutes les possibilités 63001 aient été générées, je pense que nous pouvons utiliser l'expression ci-dessous. Par exemple, voici le calcul pour une probabilité supérieure à 1/2 , et ici pour supérieure à 9/10 .
shuf
c'est relativement récent - je l'ai vu sur les systèmes Ubuntu au cours des deux dernières années, mais pas sur le RHEL / CentOS actuel.