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

6

Estou procurando maneiras de usar /dev/random (ou /dev/urandom ) na linha de comando. Em particular, gostaria de saber como usar esse fluxo como stdin para 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 incluiria inteiros assinados e não assinados de 64 bits e números de ponto flutuante de 64 bits. No que diz respeito a intervalos, os intervalos máximos para os vários tipos numéricos serão suficientes.

Eu sei fazer tudo isso com intérpretes de uso geral 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 muito mínima do Unix".)

Basicamente, o problema reduz a conversão de dados binários para suas representações de string na linha de comando. (Por exemplo, isso não funcionará: printf '%f\n' $(head -c8 /dev/random) .)

Estou procurando por respostas independentes de shell. Além disso, a diferença entre /dev/random e /dev/urandom não é importante para essa questão. Espero que qualquer procedimento que funcione para um funcione para o outro, mesmo quando a semântica dos resultados for 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 hexdump em vez de od porque isso me facilitou a formatação da saída da maneira que eu queria;
  2. Irritante, porém, hexdump não suporta inteiros de 64 bits (wtf ???);
  3. A interface das funções precisa funcionar (por exemplo, eles devem aceitar -n5 , bem como -n 5 ), mas, considerando minhas lamentáveis habilidades de programação shell, esse foi o melhor que pude montar rapidamente. (Comentários / melhorias bem-vindos, como sempre.)

A grande surpresa que tive com este exercício foi descobrir como é difícil programar no shell o material numérico mais elementar (por exemplo, ler um float hexadecimal, ou obtenha 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'
}
    
por kjo 10.03.2016 / 16:44

3 respostas

11

Você pode usar od para obter números de /dev/random e /dev/urandom .

Por exemplo,

inteiros decimais não assinados de 2 bytes,

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

1 inteiro inteiro decimal assinado por byte,

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

inteiros decimais não assinados de 4 bytes,

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

man od para mais informações sobre od .

    
por 10.03.2016 / 17:02
3

Algumas conchas (por exemplo, bash(1) ) têm uma% "variável" de$RANDOM que fornece números aleatórios.

    
por 10.03.2016 / 23:33
1

Você pode 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
    
por 10.03.2016 / 17:30