Comment générer des nombres aléatoires en Bash?

Comment générer un nombre aléatoire dans une plage de Bash?

137
demandé sur Vlastimil 2009-07-28 19:23:15

13 réponses

Utilisation $RANDOM . Il est souvent utile en combinaison avec simple arithmétique shell. Par exemple, pour générer un nombre aléatoire entre 1 et 10:

$ echo $((1 + RANDOM % 10))
3

le générateur actuel est dans variables.c , la fonction brand() . les anciennes versions étaient une simple génératrice linéaire. La Version 4.0 de bash utilise un générateur avec une citation à un papier de 1985, qui probablement ça veut dire que c'est une bonne source de pseudo-nombres. Je ne l'utiliserais pas pour une simulation (et certainement pas pour la cryptographie), mais il est probablement adéquat pour les tâches de script de base.

si vous faites quelque chose qui nécessite des nombres aléatoires sérieux, vous pouvez utiliser /dev/random ou /dev/urandom s'ils sont disponibles:

$ dd if=/dev/urandom count=4 bs=1 | od -t d
161
répondu Nelson 2017-07-27 08:04:44

s'il vous Plaît voir $RANDOM :

$RANDOM est une fonction interne de Bash (pas une constante) qui renvoie un pseudo entier dans la gamme 0 - 32767. Il ne devrait pas être utilisé pour générer une clé de chiffrement.

53
répondu Andrew Hare 2009-07-28 15:24:31

Essayez ce à partir de votre shell:

$ od -A n -t d -N 1 /dev/urandom

ici, -t d spécifie que le format de sortie doit être signé décimal; -N 1 dit de lire un octet de /dev/urandom .

27
répondu Barun 2014-03-11 11:57:24

vous pouvez également obtenir un nombre aléatoire de awk

awk 'BEGIN {
   # seed
   srand()
   for (i=1;i<=1000;i++){
     print int(1 + rand() * 100)
   }
}'
14
répondu ghostdog74 2009-07-28 23:41:31

il y a $ RANDOM. Je ne sais pas exactement comment il fonctionne. Mais il fonctionne. Pour les tests, vous pouvez faire:

echo $RANDOM
14
répondu Antoine Claval 2014-03-11 11:57:02

vous pouvez également utiliser shuf (disponible en coreutils).

shuf -i 1-100000 -n 1
12
répondu knipwim 2016-08-10 05:52:34

nombre aléatoire entre 0 et 9 inclusivement.

echo $((RANDOM%10))
9
répondu David Newcomb 2014-02-24 11:37:22

Si vous utilisez un système linux, vous pouvez obtenir un nombre aléatoire de /dev/random ou /dev/urandom. Be carefull / dev / random bloquera s'il n'y a pas assez de nombres aléatoires disponibles. Si vous avez besoin de vitesse sur randomness utiliser /dev/urandom.

ces" fichiers " seront remplis de nombres aléatoires générés par le système d'exploitation. Cela dépend de l'implémentation de /dev/random sur votre système Si vous obtenez des nombres aléatoires vrais ou pseudo. Vrai des nombres aléatoires sont générés avec l'aide du bruit de forme recueilli de pilotes de périphérique comme la souris, le disque dur, le réseau.

vous pouvez obtenir des nombres aléatoires à partir du fichier avec dd

5
répondu Janusz 2009-07-28 16:47:00

j'ai pris quelques-unes de ces idées et fait une fonction qui devrait fonctionner rapidement si beaucoup de nombres aléatoires sont nécessaires.

appel od est cher si vous avez besoin de beaucoup de nombres aléatoires. Au lieu de cela je l'appelle une fois et stocke 1024 nombres aléatoires de /dev/urandom. Lorsque rand est appelé, le dernier nombre aléatoire est retourné et mis à l'échelle. Il est ensuite retiré du cache. Lorsque le cache est vide, un autre 1024 nombres aléatoires est lu.

Exemple:

rand 10; echo $RET

renvoie un nombre aléatoire dans RET entre 0 et 9 inclusivement.

declare -ia RANDCACHE
declare -i RET RAWRAND=$(( (1<<32)-1 ))

function rand(){  # pick a random number from 0 to N-1. Max N is 2^32
  local -i N=
  [[ ${#RANDCACHE[*]} -eq 0 ]] && { RANDCACHE=( $(od -An -tu4 -N1024 /dev/urandom) ); }  # refill cache
  RET=$(( (RANDCACHE[-1]*N+1)/RAWRAND ))  # pull last random number and scale
  unset RANDCACHE[${#RANDCACHE[*]}-1]     # pop read random number
};

# test by generating a lot of random numbers, then effectively place them in bins and count how many are in each bin.

declare -i c; declare -ia BIN

for (( c=0; c<100000; c++ )); do
  rand 10
  BIN[RET]+=1  # add to bin to check distribution
done

for (( c=0; c<10; c++ )); do
  printf "%d %d\n" $c ${BIN[c]} 
done

mise à jour: cela ne fonctionne pas si bien pour tous les N. il gaspille aussi des bits aléatoires si utilisé avec de petits N. notant que (dans ce cas) un nombre aléatoire de 32 bits a assez d'entropie pour 9 nombres aléatoires entre 0 et 9 (10* 9=1,000,000,000 <= 2 *32) nous pouvons extraire plusieurs nombres aléatoires de chaque valeur de 32 sources aléatoires.

#!/bin/bash

declare -ia RCACHE

declare -i RET             # return value
declare -i ENT=2           # keep track of unused entropy as 2^(entropy)
declare -i RND=RANDOM%ENT  # a store for unused entropy - start with 1 bit

declare -i BYTES=4         # size of unsigned random bytes returned by od
declare -i BITS=8*BYTES    # size of random data returned by od in bits
declare -i CACHE=16        # number of random numbers to cache
declare -i MAX=2**BITS     # quantum of entropy per cached random number
declare -i c

function rand(){  # pick a random number from 0 to 2^BITS-1
  [[ ${#RCACHE[*]} -eq 0 ]] && { RCACHE=( $(od -An -tu$BYTES -N$CACHE /dev/urandom) ); }  # refill cache - could use /dev/random if CACHE is small
  RET=${RCACHE[-1]}              # pull last random number and scale
  unset RCACHE[${#RCACHE[*]}-1]  # pop read random number
};

function randBetween(){
  local -i N=
  [[ ENT -lt N ]] && {  # not enough entropy to supply ln(N)/ln(2) bits
    rand; RND=RET       # get more random bits
    ENT=MAX             # reset entropy
  }
  RET=RND%N  # random number to return
  RND=RND/N  # remaining randomness
  ENT=ENT/N  # remaining entropy
};

declare -ia BIN

for (( c=0; c<100000; c++ )); do
  randBetween 10
  BIN[RET]+=1
done

for c in ${BIN[*]}; do
  echo $c
done
3
répondu philcolbourn 2014-02-22 22:40:15

la lecture des fichiers spéciaux de caractères /dev/random ou /dev/urandom est la voie à suivre.

ces appareils renvoient des nombres vraiment aléatoires lorsqu'ils sont lus et sont conçus pour aider les logiciels d'application à choisir des clés de cryptage sécurisées. Tel les nombres aléatoires sont extraits d'un pool d'entropie qui est fourni par divers événements aléatoires. {LDD3, Jonathan Corbet, Alessandro Rubini, and Greg Kroah-Hartman]

ces deux fichiers sont l'interface pour la randomisation du noyau, en particulier

void get_random_bytes_arch(void* buf, int nbytes)

qui tire vraiment des octets aléatoires du matériel si une telle fonction est par matériel implémenté (est généralement), ou il tire de Entropy pool (composé de minuteries entre des événements comme les interruptions de souris et de clavier et d'autres interruptions qui sont enregistrés avec SA_SAMPLE_RANDOM).

dd if=/dev/urandom count=4 bs=1 | od -t d

cela fonctionne, mais écrit la sortie inutile de dd à stdout. Commande ci-dessous donne juste l'entier dont j'ai besoin. Je peux même obtenir le nombre spécifié de bits aléatoires comme j'ai besoin en ajustant le bitmask donné à l'expansion arithmétique:

me@mymachine:~/$ x=$(head -c 1 /dev/urandom > tmp && hexdump 
                         -d tmp | head -n 1 | cut -c13-15) && echo $(( 10#$x & 127 ))
2
répondu 4pie0 2015-10-05 14:34:50

j'aime cette astuce:

echo ${RANDOM:0:1} # random number between 1 and 9
echo ${RANDOM:0:2} # random number between 1 and 99

...

2
répondu fraff 2017-09-20 11:09:57

génère un nombre aléatoire dans l'intervalle de 0 à n (entier 16 bits signé). Résultat défini dans la variable $RAND. Par exemple:

#!/bin/bash

random()
{
    local range=${1:-1}

    RAND=`od -t uI -N 4 /dev/urandom | awk '{print }'`
    let "RAND=$RAND%($range+1)"
}

n=10
while [ $(( n -=1 )) -ge "0" ]; do
    random 500
    echo "$RAND"
done
0
répondu Pavel Bashinsky 2013-09-05 00:13:37

Ce sujet:

perl -e 'print int rand 10, "\n"; '
0
répondu k-h 2014-05-08 10:30:53