Sto cercando modi per usare /dev/random
(o /dev/urandom
) dalla riga di comando. In particolare, vorrei sapere come utilizzare un flusso tale stdin
da scrivere flussi di numeri casuali su stdout
(un numero per riga).
Sono interessato a numeri casuali per tutti i tipi numerici che l'architettura della macchina supporta in modo nativo. Ad esempio, per un'architettura a 64 bit, questi includono numeri interi con segno e senza segno a 64 bit e numeri in virgola mobile a 64 bit. Per quanto riguarda gli intervalli, lo faranno gli intervalli massimi per i vari tipi numerici.
So come fare tutto questo con interpreti per tutti gli usi come Perl, Python, ecc., Ma mi piacerebbe saperlo fare con strumenti "più semplici" dalla shell. (Per "più semplice" intendo "più probabilità di essere disponibile anche in un'installazione Unix molto minimale".)
Fondamentalmente il problema riduce quello della conversione dei dati binari nelle loro rappresentazioni di stringa sulla riga di comando. (Ad esempio, questo non farà:. printf '%f\n' $(head -c8 /dev/random)
)
Sto cercando risposte agnostiche alla shell. Inoltre, la differenza tra /dev/random
e /dev/urandom
non è importante per questa domanda. Mi aspetto che qualsiasi procedura che funzioni per uno funzionerà per l'altro, anche quando la semantica dei risultati potrebbe differire.
Ho adattato la risposta di EightBitTony per produrre le funzioni toints
, ecc. Mostrate di seguito.
Esempio di utilizzo:
% < /dev/urandom toprobs -n 5
0.237616281778928
0.85578479125532
0.0330049682019756
0.798812391655243
0.138499033902422
Osservazioni:
- Sto usando
hexdump
inveceod
perché mi ha dato un modo più semplice per formattare l'output nel modo desiderato; - Purtroppo,
hexdump
non supporta numeri interi a 64 bit (wtf ???); - L'interfaccia delle funzioni ha bisogno di lavoro (es. Dovrebbero accettare
-n5
e anche-n 5
), ma data la mia pietosa abilità di programmazione della shell, questa è stata la migliore che ho potuto mettere insieme rapidamente. (Commenti / miglioramenti sono benvenuti, come sempre.)
La grande sorpresa che ho avuto da questo esercizio è stata scoprire quanto sia difficile programmare sulla shell le cose numeriche più elementari (ad esempio leggere un float esadecimale o ottenere il massimo valore 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
dovrebbe darti solo un numero intero.