web-dev-qa-db-fra.com

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

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

179
woakas

Utilisez $RANDOM . C'est souvent utile en combinaison avec l'arithmétique simple de Shell. Par exemple, pour générer un nombre aléatoire compris entre 1 et 10:

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

Le générateur actuel est en _variables.c_, la fonction brand(). Anciennes versions étaient un simple générateur linéaire. La version 4.0 de bash utilise un générateur avec une citation à un article de 1985, ce qui signifie probablement que c'est une source décente de nombres pseudo-aléatoires. Je ne l'utiliserais pas pour une simulation (et certainement pas pour la cryptographie), mais c'est probablement suffisant 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
_
217
Nelson

Veuillez voir $RANDOM :

_$RANDOM_ est une fonction Bash interne (et non une constante) qui renvoie un entier pseudo-aléatoire compris entre 0 et 32767. Elle ne doit pas être utilisée pour générer une clé de cryptage.

63
Andrew Hare

Essayez ceci depuis 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.

32
Barun

Vous pouvez également utiliser shuf (disponible dans les coreutils).

shuf -i 1-100000 -n 1
27
knipwim

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)
   }
}'
19
ghostdog74

Il y a $ RANDOM. Je ne sais pas exactement comment ça marche. Mais ça marche. Pour tester, vous pouvez faire:

echo $RANDOM
18
Antoine Claval

Nombre aléatoire compris entre 0 et 9 inclus.

echo $((RANDOM%10))
10
David Newcomb

J'aime cette astuce:

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

...

8
fraff

Si vous utilisez un système Linux, vous pouvez obtenir un nombre aléatoire parmi / dev/random o /dev/urandom. Attention, dev/random bloquera s'il n'y a pas assez de nombres aléatoires disponibles. Si vous avez besoin de vitesse plutôt que d’aléatoire, utilisez/dev/urandom.

Ces "fichiers" seront remplis avec des 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 vrais ou pseudo aléatoires. Les vrais nombres aléatoires sont générés avec l'aide du bruit provenant des pilotes de périphérique tels que souris, disque dur, réseau.

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

5
Janusz

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

Ces périphériques renvoient des nombres réellement aléatoires lors de la lecture et sont conçus pour aider les applications à choisir des clés sécurisées pour le cryptage. Ces nombres aléatoires sont extraits d'un pool d'entropie généré par divers événements aléatoires. {LDD3, Jonathan Corbet, Alessandro Rubini et Greg Kroah-Hartman]

Ces deux fichiers sont une interface pour la randomisation du noyau, en particulier

void get_random_bytes_Arch(void* buf, int nbytes)

qui tire des octets véritablement aléatoires du matériel si cette fonction est implémentée par le matériel (généralement), ou du pool d'entropie (composé de minutages entre des événements tels que des interruptions de souris et de clavier et d'autres interruptions enregistrées avec SA_SAMPLE_RANDOM).

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

Cela fonctionne, mais écrit les sorties inutiles de dd sur stdout. La commande ci-dessous donne juste le nombre entier dont j'ai besoin. Je peux même obtenir le nombre spécifié de bits aléatoires dont j'ai besoin en ajustant le masque binaire donné au développement arithmétique:

me@mymachine:~/$ x=$(head -c 1 /dev/urandom > tmp && hexdump 
                         -d tmp | head -n 1 | cut -c13-15) && echo $(( 10#$x & 127 ))
4
4pie0

J'ai repris quelques-unes de ces idées et créé une fonction qui devrait fonctionner rapidement si de nombreux nombres aléatoires sont requis.

appeler od est coûteux 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 dans/dev/urandom. Lorsque vous appelez Rand, le dernier nombre aléatoire est renvoyé et mis à l'échelle. Il est ensuite retiré du cache. Lorsque le cache est vide, 1024 autres nombres aléatoires sont lus.

Exemple:

Rand 10; echo $RET

Retourne un nombre aléatoire dans RET compris entre 0 et 9 inclus.

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=$1
  [[ ${#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

UPDATE: Cela ne fonctionne pas très bien pour tous les N. Il gaspille également des bits aléatoires s’il est utilisé avec un petit N. Notant que (dans ce cas) un nombre aléatoire de 32 bits a assez d’entropie pour 9 nombres aléatoires compris entre 0 et 9 (10 * - 9 = 1 000 000 000 <= 2 * 32) nous pouvons extraire plusieurs nombres aléatoires de chaque valeur source 32 aléatoire.

#!/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=$1
  [[ 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
4
philcolbourn

Qu'en est-il de:

Perl -e 'print int Rand 10, "\n"; '
2
k-h

Peut-être suis-je un peu en retard, mais qu'en est-il de l'utilisation de jot pour générer un nombre aléatoire dans une plage de Bash?

jot -r -p 3 1 0 1

Cela génère un nombre aléatoire (-r) avec une précision de 3 décimales (-p). Dans ce cas particulier, vous obtiendrez un nombre compris entre 0 et 1 (1 0 1). Vous pouvez également imprimer des données séquentielles. La source du nombre aléatoire, selon le manuel, est:

Les nombres aléatoires sont obtenus par arc4random (3) lorsqu'aucune graine n'est spécifiée, et par aléatoire (3) lorsqu'une graine est donnée.

2
Vinicius Placco

Générez un nombre aléatoire compris entre 0 et n (entier signé de 16 bits). 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 $2}'`
    let "Rand=$Rand%($range+1)"
}

n=10
while [ $(( n -=1 )) -ge "0" ]; do
    random 500
    echo "$Rand"
done
1
Pavel Bashinsky