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 stdin
para 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/random
y /dev/urandom
no 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:
- Estoy usando en
hexdump
lugar deod
porque me dio una forma más fácil de formatear la salida de la manera que quería; - Sin embargo, molestamente,
hexdump
no admite enteros de 64 bits (wtf ???); - La interfaz de las funciones necesita trabajo (por ejemplo, deberían aceptarlas
-n5
tambié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'
}
tr -cs '[:digit:]' '[\n*]' </dev/urandom
debería darte solo un número entero.