Estou procurando maneiras de usar /dev/random
(ou /dev/urandom
) na linha de comando. Em particular, eu gostaria de saber como usar esse fluxo 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 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/random
e /dev/urandom
nã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:
- Estou usando, em
hexdump
vez de,od
porque me deu uma maneira mais fácil de formatar a saída da maneira que eu queria; - Irritantemente, porém,
hexdump
não suporta números inteiros de 64 bits (wtf ???); - A interface das funções precisa funcionar (por exemplo, elas devem aceitar
-n5
també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'
}
tr -cs '[:digit:]' '[\n*]' </dev/urandom
deve fornecer apenas um número inteiro.