Utilisation de / dev / random, / dev / urandom pour générer des données aléatoires

12

Je cherche des moyens d'utiliser /dev/random(ou /dev/urandom) à partir de la ligne de commande. En particulier, j'aimerais savoir comment utiliser un tel flux stdinpour écrire des flux de nombres aléatoires vers stdout(un numéro par ligne).

Je suis intéressé par les nombres aléatoires pour tous les types numériques pris en charge nativement par l'architecture de la machine. Par exemple, pour une architecture 64 bits, ceux-ci comprendraient des entiers signés et non signés 64 bits et des nombres à virgule flottante 64 bits. En ce qui concerne les plages, les plages maximales pour les différents types numériques feront l'affaire.

Je sais comment faire tout cela avec des interprètes polyvalents comme Perl, Python, etc., mais j'aimerais savoir comment le faire avec des outils "plus simples" du shell. (Par "plus simple", je veux dire "plus susceptible d'être disponible même dans une installation Unix très minimale".)

Fondamentalement, le problème réduit celui de la conversion des données binaires en leurs représentations de chaîne sur la ligne de commande. (Par exemple, cela ne fera pas:. printf '%f\n' $(head -c8 /dev/random))

Je cherche des réponses indépendantes de l'environnement. En outre, la différence entre /dev/randomet /dev/urandomn'est pas importante pour cette question. Je m'attends à ce que toute procédure qui fonctionne pour l'un fonctionne pour l'autre, même lorsque la sémantique des résultats peut différer.


J'ai adapté la réponse d'EightBitTony pour produire les fonctions toints, etc. ci-dessous.

Exemple d'utilisation:

% < /dev/urandom toprobs -n 5
0.237616281778928
0.85578479125532
0.0330049682019756
0.798812391655243
0.138499033902422

Remarques:

  1. J'utilise hexdumpau lieu de odparce que cela m'a donné un moyen plus facile de formater la sortie comme je le voulais;
  2. Malheureusement, hexdumpne prend pas en charge les entiers 64 bits (wtf ???);
  3. L'interface des fonctions a besoin de travail (par exemple, elles devraient accepter -n5aussi bien que -n 5), mais étant donné mes pitoyables compétences en programmation shell, c'était le mieux que j'ai pu assembler rapidement. (Commentaires / améliorations bienvenus, comme toujours.)

La grande surprise que j'ai eue de cet exercice a été de découvrir à quel point il est difficile de programmer sur le shell les éléments numériques les plus élémentaires (par exemple lire un flottant hexadécimal, ou obtenir la valeur flottante native maximale) ...


_tonums () {
  local FUNCTION_NAME=$1 BYTES=$2 CODE=$3
  shift 3

  local USAGE="Usage: $FUNCTION_NAME [-n <INTEGER>] [FILE...]"
  local -a PREFIX

  case $1 in
    ( -n ) if (( $# > 1 ))
           then
               PREFIX=( head -c $(( $2 * $BYTES )) )
               shift 2
           else
               echo $USAGE >&2
               return 1
           fi ;;
    ( -* ) echo $USAGE >&2
           return 1 ;;
    (  * ) PREFIX=( cat ) ;;
  esac

  local FORMAT=$( printf '"%%%s\\n"' $CODE )
  $PREFIX "$@" | hexdump -ve $FORMAT
}

toints () {
  _tonums toints 4 d "$@"
}

touints () {
  _tonums touints 4 u "$@"
}

tofloats () {
  _tonums tofloats 8 g "$@"
}

toprobs () {
  _tonums toprobs 4 u "$@" | perl -lpe '$_/=4294967295'
}
kjo
la source
1
tr -cs '[:digit:]' '[\n*]' </dev/urandomdevrait vous donner uniquement un nombre entier.
cuonglm
pour autant que je sache, / dev / random ne génère pas de nombres aléatoires en soi, mais ajoute du bruit aux fonctions mathématiques qui donnent un nombre pseudo-aléatoire pour qu'elles deviennent moins prévisibles. Vous voudrez peut-être regarder randomlib.sourceforge.net
Rui F Ribeiro
Avez-vous besoin d'un caractère aléatoire de qualité cryptographique ou, par exemple, l'ensemencement basé sur le temps est-il suffisant?
Gilles 'SO- arrête d'être méchant'
@Gilles: la motivation de ma question était plus de se renseigner sur les outils shell et Unix que sur le hasard; Je voulais juste savoir quels outils Unix de base existaient pour convertir un flux de données binaires en leur représentation sous forme de chaîne.
kjo

Réponses:

21

Vous pouvez utiliser odpour extraire des nombres de /dev/randomet /dev/urandom.

Par exemple,

Entiers décimaux non signés de 2 octets,

$ od -vAn -N2 -tu2 < /dev/urandom
24352

Entier décimal signé de 1 octet,

$ od -vAn -N1 -td1 < /dev/urandom
-78

Entiers décimaux non signés de 4 octets,

$ od -vAn -N4 -tu4 < /dev/urandom
3394619386

man odpour plus d'informations sur od.

EightBitTony
la source
8

Certains obus (par exemple bash(1)) ont une $RANDOM"variable" qui donne des nombres aléatoires.

vonbrand
la source
1

Vous pourriez faire quelque chose comme:

perl -le '
  while (q(
    c char,  C unsigned char, s! short, S! unsigned short,
    i! int,  I! unsigned int, l! long,  L! unsigned long,
    f float, d double,) =~ /(\S+) (.*?),/gs) {
    $size = length(pack $1, 0);
    sysread STDIN, $data, $size;
    print "$2($size): " . unpack($1, $data);
  }' < /dev/urandom

Ce qui sur un système 64 bits vous donnerait quelque chose comme:

char(1): -98
unsigned char(1): 62
short(2): -12526
unsigned short(2): 399
int(4): 499066219
unsigned int(4): 2312134917
long(8): -4889591208978026255
unsigned long(8): 2080566823379835456
float(4): 55.4727554321289
double(8): 8.6395690272822e-05
Stéphane Chazelas
la source