Nombre aléatoire à partir d'une plage dans un Script Bash
J'ai besoin de générer un numéro de port aléatoire entre 2000-65000
à partir d'un script shell. Le problème est $RANDOM
est à 15-nombre de bits, donc je suis coincé!
PORT=$(($RANDOM%63000+2001))
fonctionnerait bien si ce n'était pas pour la limitation de la taille.
Quelqu'un aurait-il un exemple de la façon dont je peux le faire, peut-être par l'extraction d'un élément de /dev/urandom
et de le faire à l'intérieur d'une gamme?
Vous devez vous connecter pour publier un commentaire.
Profitez-en!
Modifier: La plage est inclus.
shuf
est relativement récente, je l'ai vu sur les systèmes Ubuntu dans les deux dernières années, mais non pas de la RHEL/CentOS.shuf
fait de permuter l'ensemble de l'entrée. Cela en fait un mauvais choix si vous êtes à la génération de nombres aléatoires très fréquemment.time for i in {1..1000}; do shuf -i 0-$end -n 1000 > /dev/null; done
et en comparantend=1
àend=65535
a montré environ 25% d'amélioration pour la plus courte portée qui s'élevait à environ 4 secondes de différence de plus d'un million d'itérations. Et c'est beaucoup plus rapide que d'effectuer des OP Bash calcul d'un million de fois.-n 1
ont montré négligeable des différences de temps, même avecend=4000000000
. Bon à savoirshuf
œuvres intelligent, pas difficile 🙂brew install coreutils
. Les commandes sont installés avec le préfixeg
, donc ça va êtregshuf
.backupDst="$backup_dir/$backup_name$(date +%d%m%y)_$(cat /dev/urandom | tr -dc 'a-z' | fold -w 4 | head -n 1).xlsm"
aveccat /dev/urandom
être le coupable. À l'aide debackupDst="$backup_dir/$backup_name$(date +%d%m%y)_$(shuf -i '1000-9999' -n '1').xlsm"
fixe tout de suite. Cheers!d1=$(shuf -i '0-9' -n '1') d2=$(shuf -i '0-9' -n '1') d3=$(shuf -i '0-9' -n '1') d4=$(shuf -i '0-9' -n '1') echo $d1$d2$d3$d4
Assez sûr qu'il est plus élégant de moyens, notamment en termes de SEC, mais cela permet de nombres aléatoires avec 4 chiffres avec des zéros.shuf
ne pas utiliser d'un point de vue cryptographique sécurisé générateur de nombre aléatoire par défaut. Ajouter--random-source=/dev/urandom
si c'est ce que vous avez besoin.Sur Mac OS X et FreeBSD, vous pouvez également utiliser iota:
jot
a une distribution inéquitable pour l'intervalle de temps minimum et maximum (c'est à dire, en 2000 et en 65000). En d'autres termes, le min et le max sera généré moins fréquemment. Voir mon iota réponse 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 de bash,
$RANDOM
est distribué entre 0 et 32767; c'est, c'est un unsigned 15 bits de la valeur. En supposant que$RANDOM
est distribuée de manière uniforme, vous pouvez créer un distribuée uniformément unsigned 30 bits entier comme suit:Depuis votre gamme n'est pas une puissance de 2, un simple modulo ne presque vous donner une distribution uniforme, mais avec un 30 bits d'entrée de gamme et un moins-que-16-bits sortie de la gamme, que vous avez dans votre cas, cela devrait vraiment être assez proche:
$RANDOM
n'est pas toujours disponible dans toutes les coquilles. La recherche d'une autre solutionet voici un avec Python
et une avec awk
RANDOM
n'est pas garanti par POSIX,-S
optionImportError: No module named random
. Fonctionne si je le supprimer. Pas sûr de ce que ghostdog a l'intention pour que.python -S -c "import random; print random.randrange(2000,63000)"
semble bien fonctionner. Cependant, lorsque j'essaie d'obtenir un nombre aléatoire entre 1 et 2, j'ai l'impression de toujours obtenir 1... les Pensées?random.randint
au lieu derandom.randrange
œuvres.srand
, il va utiliser la date et l'heure actuelles. Trouvé ici (a plus d'info aussi) stackoverflow.com/a/4048538/1737158La plus simple manière générale qui vient à l'esprit est une interface one-liner:
Vous pouvez toujours utiliser deux numéros:
Vous avez encore de clip de votre gamme. Ce n'est pas un général à n bits nombre aléatoire de la méthode, mais il va travailler pour votre cas, et c'est tout l'intérieur de bash.
Si vous voulez être vraiment mignon et lire à partir de /dev/urandom, vous pourriez faire ceci:
Qui vais vous lire deux octets et de les imprimer comme un unsigned int; il vous reste à faire votre écrêtage.
awk
version d'une autre réponseEn voici un autre. J'ai pensé qu'il serait de travailler sur à peu près tout, mais en quelque sorte de l'option aléatoire n'est pas disponible sur mon centos boîte au travail.
sort -R
n'est pas disponible sur OS X soit.$RANDOM
est un nombre compris entre 0 et 32767. Vous voulez un port entre 2000 et 65000. Ce sont 63001 possible ports. Si nous nous en tenons à des valeurs de$RANDOM + 2000
entre 2000 et 33500, nous couvrons une gamme de 31501 ports. Si on lance une pièce de monnaie puis conditionnellement ajouter 31501 le résultat, nous pouvons obtenir plus de ports, de 33501 à 65001. Alors, si nous suffit de les déposer 65001, nous obtenir la couverture nécessaire, avec une distribution de probabilité uniforme pour tous les ports, il me semble.Tests
Si vous n'êtes pas un coup d'experts et ont été à la recherche pour obtenir ce dans une variable dans une base Linux script bash, essayez ceci:
VAR=$(shuf -i 200-700 -n 1)
Qui vous mène à la plage de 200 à 700 en
$VAR
, inclusivement.Vous pouvez le faire
Si vous avez besoin de plus de détails, voir Shell Script Générateur De Nombre Aléatoire.
Même avec ruby:
Bash documentation dit que chaque fois
$RANDOM
est référencé, un nombre aléatoire entre 0 et 32767 est retourné. Si nous somme deux fois de suite les références, nous obtenons des valeurs de 0 à 65534, qui couvre toute la gamme de 63001 possibilités pour un nombre aléatoire entre 2000 et 65000.Pour l'ajuster à la portée exacte, nous utilisons la somme modulo 63001, ce qui va nous donner une valeur de 0 à 63000. Ce à son tour, a juste besoin d'une augmentation en 2000 pour les besoins de nombre aléatoire, entre 2000 et 65000. Cela peut être résumée comme suit:
Tests
Exactitude du calcul
Voici une, force brute de test pour la justesse du calcul. Ce programme essaie juste de générer tous les 63001 différentes possibilités au hasard, en utilisant le calcul en cours de test. Le
--jobs
paramètre doit faire courir plus vite, mais ce n'est pas déterministe (total de possibilités généré peut être inférieur 63001).De déterminer combien d'itérations sont nécessaires pour obtenir une probabilité donnée
p/q
de tous les 63001 possibilités ayant été générées, je crois que nous pouvons utiliser l'expression ci-dessous. Par exemple, voici le calcul pour une probabilité supérieure à 1/2, et ici pour plus de 9/10.$RANDOM
est un entier. Avec votre "truc" il y a beaucoup de valeurs qui ne sera jamais atteint.-1
.$RANDOM
au lieu de cela, et ne pas refactoriser que dans une multiplication par deux, depuis$RANDOM
est censé changer à chaque accès. J'ai mis à jour la réponse avec la somme de version.RANDOM+RANDOM
ne vous donnera pas un uniforme répartition des nombres aléatoires entre 0 et 65534.Ou sur OS-X le suivant fonctionne pour moi:
PORT=$(($RANDOM%63000+2001))
est proche de ce que vous voulez, je pense.PORT=$(($RANDOM$RANDOM$RANDOM%63000+2001))
permet de contourner la limitation de la taille qui vous trouble. Depuis bash ne fait aucune distinction entre un nombre variable et une variable de chaîne, cela fonctionne parfaitement bien. Le "nombre"$RANDOM
peuvent être concaténés comme une corde, et de l'utiliser comme un certain nombre dans un calcul. Incroyable!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 à travers
urandom
head -200 /dev/urandom | cksum
De sortie:
3310670062 52870
Pour récupérer une part du nombre ci-dessus.
head -200 /dev/urandom | cksum | cut -f1 -d " "
Alors la sortie est
3310670062
Pour répondre à votre exigence,
head -200 /dev/urandom |cksum | cut -f1 -d " " | awk '{print $1%63000+2001}'
C'est la façon dont j'ai l'habitude de générer des nombres aléatoires. Puis-je utiliser "NUM_1" comme la variable pour le numéro de port que j'utilise. Voici un court exemple de script.