Usando / dev / random, / dev / urandom para generar datos aleatorios

12

Estoy buscando formas de usar /dev/random(o /dev/urandom) desde la línea de comandos. En particular, me gustaría saber cómo usar una secuencia stdinpara escribir secuencias de números aleatorios en stdout(un número por línea).

Estoy interesado en números aleatorios para todos los tipos numéricos que la arquitectura de la máquina admite de forma nativa. Por ejemplo, para una arquitectura de 64 bits, estos incluirían enteros con y sin signo de 64 bits y números de coma flotante de 64 bits. En cuanto a los rangos, los rangos máximos para los diversos tipos numéricos serán suficientes.

Sé cómo hacer todo esto con intérpretes multipropósito como Perl, Python, etc., pero me gustaría saber cómo hacerlo con herramientas "más simples" del shell. (Por "más simple" quiero decir "es más probable que esté disponible incluso en una instalación mínima de Unix").

Básicamente, el problema reduce el de convertir datos binarios a sus representaciones de cadena en la línea de comando. (Por ejemplo, esto no servirá:. printf '%f\n' $(head -c8 /dev/random))

Estoy buscando respuestas agnósticas de concha. Además, la diferencia entre /dev/randomy /dev/urandomno es importante para esta pregunta. Espero que cualquier procedimiento que funcione para uno funcione para el otro, incluso cuando la semántica de los resultados puede diferir.


Adapte la respuesta de EightBitTony para producir las funciones toints, etc. que se muestran a continuación.

Ejemplo de uso:

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

Observaciones:

  1. Estoy usando en hexdumplugar de odporque me dio una forma más fácil de formatear la salida de la manera que quería;
  2. Sin embargo, molestamente, hexdumpno admite enteros de 64 bits (wtf ???);
  3. La interfaz de las funciones necesita trabajo (por ejemplo, deberían aceptarlas -n5también -n 5), pero dada mi lamentable habilidad de programación de shell, esto fue lo mejor que pude armar rápidamente. (Comentarios / mejoras bienvenidas, como siempre).

La gran sorpresa que obtuve de este ejercicio fue descubrir lo difícil que es programar en el shell las cosas numéricas más elementales (por ejemplo, leer un flotante hexadecimal u obtener el valor máximo de flotante nativo) ...


_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
fuente
1
tr -cs '[:digit:]' '[\n*]' </dev/urandomdebería darte solo un número entero.
Cuonglm
Que yo sepa, / dev / random no genera números aleatorios per se, pero agrega ruido a las funciones matemáticas que dan un número pseudoaleatorio para que sean menos predecibles. Es posible que desee mirar randomlib.sourceforge.net
Rui F Ribeiro
¿Necesita aleatoriedad de calidad criptográfica o, por ejemplo, la siembra se basa en el tiempo lo suficientemente bueno?
Gilles 'SO- deja de ser malvado'
@Gilles: la motivación de mi pregunta fue más sobre las herramientas de shell y Unix que sobre la aleatoriedad; Solo quería saber qué herramientas básicas de Unix existían para convertir un flujo de datos binarios en su representación de cadena.
kjo

Respuestas:

21

Puede usar odpara obtener números de /dev/randomy /dev/urandom.

Por ejemplo,

Enteros decimales sin signo de 2 bytes,

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

1 byte entero decimal con signo,

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

Enteros decimales sin signo de 4 bytes,

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

man odPara más información sobre od.

OchoBitTony
fuente
8

Algunas conchas (por ejemplo bash(1)) tienen una $RANDOM"variable" que da números aleatorios.

vonbrand
fuente
1

Podrías hacer algo como:

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

Lo que en un sistema de 64 bits le daría algo como:

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
fuente