Après avoir googlé un peu, je n'ai pas pu trouver un moyen simple d'utiliser une commande Shell pour générer un nombre entier décimal aléatoire inclus dans une plage spécifique, c'est-à-dire entre un minimum et un maximum.
Je lis à propos de /dev/random
, /dev/urandom
et $RANDOM
, mais rien de tout cela ne peut faire ce dont j'ai besoin.
Existe-t-il une autre commande utile ou un moyen d'utiliser les données précédentes?
Dans le POSIX toolchest, vous pouvez utiliser awk
:
awk -v min=5 -v max=10 'BEGIN{srand(); print int(min+Rand()*(max-min+1))}'
Utilisez pas comme source pour générer des mots de passe ou des données secrètes par exemple, comme avec la plupart des implémentations awk
, le nombre peut facilement être deviné en fonction de l'heure à laquelle la commande a été exécutée.
Avec de nombreuses implémentations awk
, cette commande exécutée deux fois dans la même seconde vous donnera généralement la même sortie.
Vous pouvez essayer shuf
depuis GNU coreutils:
shuf -i 1-100 -n 1
Sur BSD et OSX, vous pouvez utiliser jot pour renvoyer un seul aléatoire (-r
) nombre de l'intervalle min
à max
, inclus.
$ min=5
$ max=10
$ jot -r 1 $min $max
Malheureusement, la plage et la distribution des nombres générés de manière aléatoire sont influencées par le fait que jot utilise l'arithmétique à virgule flottante double précision en interne et printf (3) pour le format de sortie, ce qui provoque des problèmes d'arrondi et de troncature. Par conséquent, min
et max
de l'intervalle sont générés moins fréquemment, comme illustré:
$ jot -r 100000 5 10 | sort -n | uniq -c
9918 5
20176 6
20006 7
20083 8
19879 9
9938 10
Sur OS X 10.11 (El Capitan), cela semble avoir été corrigé:
$ jot -r 100000 5 10 | sort -n | uniq -c
16692 5
16550 6
16856 7
16579 8
16714 9
16609 10
et...
$ jot -r 1000000 1 10 | sort -n | uniq -c
100430 1
99965 2
99982 3
99796 4
100444 5
99853 6
99835 7
100397 8
99588 9
99710 10
Pour les anciennes versions d'OS X, heureusement, il existe plusieurs solutions de contournement. La première consiste à utiliser la conversion entière printf (3). La seule mise en garde est que l'intervalle maximum devient maintenant max+1
. En utilisant le formatage entier, nous obtenons une distribution équitable sur tout l'intervalle:
$ jot -w %i -r 100000 5 11 | sort -n | uniq -c
16756 5
16571 6
16744 7
16605 8
16683 9
16641 10
Enfin, pour obtenir un jet équitable des dés en utilisant la solution de contournement, nous avons:
$ min=5
$ max_plus1=11 # 10 + 1
$ jot -w %i -r 1 $min $max_plus1
Voir jot (1) pour les détails sanglants de mathématiques et de mise en forme et bien d'autres exemples.
Le $RANDOM
la variable n'est normalement pas un bon moyen de générer de bonnes valeurs aléatoires. La sortie de /dev/[u]random
doit également être converti en premier.
Un moyen plus simple consiste à utiliser des langues de niveau supérieur, comme par exemple python:
Pour générer une variable entière aléatoire entre 5 et 10 (5 <= N <= 10), utilisez
python -c "import random; print random.randint(5,10)"
Ne l'utilisez pas pour des applications cryptographiques.
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 générer une variable entière aléatoire entre 5 et 10 (y compris les deux), utilisez
echo $(( RANDOM % (10 - 5 + 1 ) + 5 ))
%
fonctionne comme un opérateur modulo.
Il existe probablement de meilleures façons de convertir la variable aléatoire $RANDOM
à une plage spécifique. Ne l'utilisez pas pour des applications cryptographiques ou dans le cas où vous avez besoin de vraies variables aléatoires à répartition égale (comme pour les simulations).
Peut-être que le UUID
(sous Linux) peut être utilisé pour récupérer le nombre aléatoire
$ cat /proc/sys/kernel/random/uuid
cdd52826-327d-4355-9737-895f58ad11b4
Pour obtenir le nombre aléatoire entre 70
et 100
POSIXLY_CORRECT=1 awk -F - '{print(("0x"$1) % 30 + 70)}
' /proc/sys/kernel/random/uuid
# echo $(( $RANDOM % 256 ))
produira un nombre "aléatoire" entre 0 et 255 dans les dialectes modernes * sh.
cat /dev/urandom | tr -dc 'a-fA-F0-9' | fold -w 8 | head -n 1
Cela générera un nombre hexadécimal de 8 chiffres.
Pour rester entièrement dans bash et utiliser la variable $ RANDOM mais éviter la distribution inégale:
#!/bin/bash
range=10
floor=20
if [ $range -gt 32768 ]; then
echo 'range outside of what $RANDOM can provide.' >&2
exit 1 # exit before entering infinite loop
fi
max_RANDOM=$(( 2**15/$range*$range ))
r=$RANDOM
until [ $r -lt $max_RANDOM ]; do
r=$RANDOM
done
echo $(( r % $range + $floor ))
Cet exemple fournirait des nombres aléatoires de 20 à 29.
La distribution est bonne:
pour ((i = 1; i <= 100000; i ++)) faire écho $ ((RANDOM% (20 - 10 + 1) + 10)); fait | sort -n | uniq -c
compter la valeur
9183 10
9109 11
8915 12
9037 13
9100 14
9138 15
9125 16
9261 17
9088 18
8996 19
9048 20
en utilisant RANDOM
MAX=999999 #Upper Range
MIN=100000 #Lower Range
DIFF=$((MAX-MIN+1)) #+1 to inlcude upper limit
R=$(($(($RANDOM%$DIFF))+MIN))
en utilisant SHUF
MIN=1000
MAX=9999
COUNT=1 #count of Random Numbers to be generated
shuf -i $MIN-$MAX -n $COUNT
shuf -i 1000-9999 -n 1
en utilisant/dev/random
od -An -N2 -i /dev/random #Generates a 2 byte Number, -N2=Generates 2 Random Number btween range 0-65535