Usando / dev / random, / dev / urandom para gerar dados aleatórios

12

Estou procurando maneiras de usar /dev/random(ou /dev/urandom) na linha de comando. Em particular, eu gostaria de saber como usar esse fluxo stdinpara gravar fluxos de números aleatórios em stdout(um número por linha).

Estou interessado em números aleatórios para todos os tipos numéricos que a arquitetura da máquina suporta nativamente. Por exemplo, para uma arquitetura de 64 bits, isso inclui números inteiros assinados e não assinados de 64 bits e números de ponto flutuante de 64 bits. No que diz respeito aos intervalos, os intervalos máximos para os vários tipos numéricos serão suficientes.

Sei como fazer tudo isso com intérpretes para todas as finalidades, como Perl, Python, etc., mas gostaria de saber como fazer isso com ferramentas "mais simples" do shell. (Por "mais simples", quero dizer "é mais provável que esteja disponível mesmo em uma instalação Unix muito mínima".)

Basicamente, o problema reduz o da conversão de dados binários em suas representações de seqüência de caracteres na linha de comando. (Por exemplo, isso não serve:. printf '%f\n' $(head -c8 /dev/random))

Estou procurando respostas agnósticas. Além disso, a diferença entre /dev/randome /dev/urandomnão é importante para esta questão. Espero que qualquer procedimento que funcione para um funcione para o outro, mesmo quando a semântica dos resultados puder ser diferente.


Eu adaptei a resposta do EightBitTony para produzir as funções toints, etc. mostradas abaixo.

Exemplo de uso:

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

Observações:

  1. Estou usando, em hexdumpvez de, odporque me deu uma maneira mais fácil de formatar a saída da maneira que eu queria;
  2. Irritantemente, porém, hexdumpnão suporta números inteiros de 64 bits (wtf ???);
  3. A interface das funções precisa funcionar (por exemplo, elas devem aceitar -n5também -n 5), mas, dada a minha lamentável habilidade em programação de shell, este foi o melhor que eu pude montar rapidamente. (Comentários / melhorias são bem-vindos, como sempre.)

A grande surpresa que obtive deste exercício foi descobrir como é difícil programar no shell as coisas numéricas mais elementares (por exemplo, ler um float hexadecimal ou obter o valor máximo de float 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
fonte
1
tr -cs '[:digit:]' '[\n*]' </dev/urandomdeve fornecer apenas um número inteiro.
cuonglm
até onde sei, / dev / random não gera números aleatórios per se, mas adiciona ruído às funções matemáticas que fornecem um número pseudo-aleatório para que se tornem menos previsíveis. Você pode querer olhar para randomlib.sourceforge.net
Rui F Ribeiro
Você precisa de aleatoriedade de qualidade criptográfica ou, por exemplo, a propagação com base no tempo suficientemente bom?
Gilles 'SO- stop being evil
@ Gilles: a motivação para minha pergunta foi mais para descobrir sobre ferramentas shell e Unix do que sobre aleatoriedade; Eu só queria saber quais ferramentas básicas do Unix existiam para converter um fluxo de dados binários em sua representação de string.
KJo

Respostas:

21

Você pode usar odpara obter números de /dev/randome /dev/urandom.

Por exemplo,

Números inteiros decimais não assinados de 2 bytes,

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

Número inteiro decimal com sinal de 1 byte,

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

Números inteiros decimais não assinados de 4 bytes,

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

man odpara mais informações sobre od.

EightBitTony
fonte
8

Algumas conchas (por exemplo bash(1)) possuem uma $RANDOM"variável" que fornece números aleatórios.

vonbrand
fonte
1

Você poderia fazer 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

Que em um sistema de 64 bits lhe daria 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
fonte