J'ai besoin de générer un numéro de port aléatoire entre 2000-65000
un script shell. Le problème est $RANDOM
un nombre de 15 bits, donc je suis coincé!
PORT=$(($RANDOM%63000+2001))
fonctionnerait bien sans la limitation de taille.
Quelqu'un at-il un exemple de la façon dont je peux le faire, peut-être en extrayant quelque chose /dev/urandom
et en le plaçant dans une plage?
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.shuf
cela permute en fait la totalité de l'entrée. Cela en fait un mauvais choix si vous générez des nombres aléatoires très fréquemment.time for i in {1..1000}; do shuf -i 0-$end -n 1000 > /dev/null; done
et la comparaisonend=1
àend=65535
montré une amélioration de 25% pour la plus courte portée qui se sont élevées à environ 4 secondes différence plus d' un million d' itérations. Et c'est beaucoup plus rapide que d'effectuer le calcul Bash de l'OP un million de fois.-n 1
montré des différences de temps négligeables, même avecend=4000000000
. Bon à savoirshuf
fonctionne intelligemment, pas dur :-)Sur Mac OS X et FreeBSD, vous pouvez également utiliser jot:
la source
jot
la distribution est injuste pour le minimum et le maximum de l'intervalle (c'est-à-dire 2000 et 65000). En d'autres termes, les valeurs min et max seront générées moins fréquemment. Voir ma réponse jot pour plus de détails et une solution de contournement.jot
est également disponible dans la plupart des distributions GNU / LinuxSelon la page de manuel bash,
$RANDOM
est répartie entre 0 et 32767; c'est-à-dire qu'il s'agit d'une valeur non signée de 15 bits. En supposant que la$RANDOM
distribution est uniforme, vous pouvez créer un entier non signé de 30 bits uniformément distribué comme suit:Étant donné que votre plage n'est pas une puissance de 2, une simple opération modulo ne vous donnera quasiment qu'une distribution uniforme, mais avec une plage d'entrée de 30 bits et une plage de sortie inférieure à 16 bits, comme vous l'avez dans votre cas, cela devrait vraiment être assez proche:
la source
$RANDOM
n'est pas toujours disponible dans tous les shells. Vous cherchez une autre solution$RANDOM
deux fois. Sur les shells qui prennent en charge$RANDOM
, une nouvelle valeur est générée chaque fois qu'elle est référencée. Donc, ce code remplit les bits 0 à 14 avec une$RANDOM
valeur et remplit les bits 15 à 29 avec une autre. En supposant qu'il$RANDOM
est uniforme et indépendant, cela couvre toutes les valeurs de 0 à 2 ** 30-1 sans rien sauter.et en voici un avec Python
et un avec awk
la source
RANDOM
n'est pas garanti par POSIX,-S
option entraîneImportError: No module named random
. Fonctionne si je supprime cela. Je ne sais pas quelle était l'intention de ghostdog.python -S -c "import random; print random.randrange(2000,63000)"
semble bien fonctionner. Cependant, quand j'essaye d'obtenir un nombre aléatoire entre 1 et 2, il me semble que j'obtiens toujours 1 ... Pensées?La manière générale la plus simple qui me vient à l'esprit est un perl one-liner:
Vous pouvez toujours simplement utiliser deux nombres:
Vous devez toujours couper à votre portée. Ce n'est pas une méthode générale de nombre aléatoire à n bits, mais cela fonctionnera pour votre cas, et tout est dans bash.
Si vous voulez être vraiment mignon et lire dans / dev / urandom, vous pouvez le faire:
Cela lira deux octets et les imprimera comme un entier non signé; vous devez toujours faire votre coupure.
la source
awk
version d'une autre réponseSi vous n'êtes pas un expert bash et que vous cherchiez à l'intégrer dans une variable dans un script bash basé sur Linux, essayez ceci:
VAR=$(shuf -i 200-700 -n 1)
Cela vous fait passer de 200 à 700
$VAR
, inclus.la source
En voici un autre. Je pensais que cela fonctionnerait sur à peu près n'importe quoi, mais l'option aléatoire de sort n'est pas disponible sur ma boîte centos au travail.
la source
sort -R
n'est pas non plus disponible sur OS X.$RANDOM
est un nombre compris entre 0 et 32767. Vous voulez un port entre 2000 et 65000. Ce sont 63001 ports possibles. Si nous nous en tenons à des valeurs$RANDOM + 2000
comprises entre 2000 et 33500 , nous couvrons une gamme de 31501 ports. Si nous lançons une pièce puis ajoutons conditionnellement 31501 au résultat, nous pouvons obtenir plus de ports, de 33501 à 65001 . Ensuite, si nous supprimons simplement 65001, nous obtenons la couverture exacte nécessaire, avec une distribution de probabilité uniforme pour tous les ports, semble-t-il.Essai
la source
Tu peux le faire
Si vous avez besoin de plus de détails, consultez Générateur de nombres aléatoires de script Shell .
la source
Même chose avec le rubis:
la source
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:
Essai
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).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 .la source
$RANDOM
est un entier . Avec votre "astuce", il existe de nombreuses valeurs qui ne seront jamais atteintes.-1
.$RANDOM
place, et ne pas refactoriser cela en une multiplication par deux, car il$RANDOM
est censé changer à chaque accès. J'ai mis à jour la réponse avec la version somme.RANDOM+RANDOM
ne vous donnera pas une distribution uniforme de nombres aléatoires entre 0 et 65534.Ou sur OS-X, les travaux suivants me conviennent:
la source
PORT=$(($RANDOM%63000+2001))
est proche de ce que tu veux je pense.PORT=$(($RANDOM$RANDOM$RANDOM%63000+2001))
contourne la limitation de taille qui vous dérange. Étant donné que bash ne fait aucune distinction entre une variable numérique et une variable chaîne, cela fonctionne parfaitement bien. Le "nombre"$RANDOM
peut être concaténé comme une chaîne, puis utilisé comme nombre dans un calcul. Incroyable!la source
x=$(( $n%63000 )
est à peu près similaire àx=$(( $n % 65535 )); if [ $x -gt 63000 ]; then x=63000
.Vous pouvez obtenir le nombre aléatoire via
urandom
head -200 /dev/urandom | cksum
Production:
3310670062 52870
Pour récupérer la partie du numéro ci-dessus.
head -200 /dev/urandom | cksum | cut -f1 -d " "
Ensuite, la sortie est
3310670062
Pour répondre à votre besoin,
head -200 /dev/urandom |cksum | cut -f1 -d " " | awk '{print $1%63000+2001}'
la source
C'est ainsi que je génère habituellement des nombres aléatoires. Ensuite, j'utilise "NUM_1" comme variable pour le numéro de port que j'utilise. Voici un court exemple de script.
la source