I'm looking for ways to use /dev/random
(or /dev/urandom
) from the command line. In particular, I'd like to know how to use such a stream as stdin
to write streams of random numbers to stdout
(one number per line).
I'm interested in random numbers for all the numeric types that the machine's architecture supports natively. E.g. for a 64-bit architecture, these would include 64-bit signed and unsigned integers, and 64-bit floating point numbers. As far as ranges go, the maximal ranges for the various numeric types will do.
I know how to do all this with all-purpose interpreters like Perl, Python, etc., but I'd like to know how to do this with "simpler" tools from the shell. (By "simpler" I mean "more likely to be available even in a very minimal Unix installation".)
Basically the problem reduces that of converting binary data to their string representations on the command line. (E.g., this won't do: printf '%f\n' $(head -c8 /dev/random)
.)
I'm looking for shell-agnostic answers. Also, the difference between /dev/random
and /dev/urandom
is not important for this question. I expect that any procedure that works for one will work for the other, even when the semantics of the results may differ.
I adapted EightBitTony's answer to produce the functions toints
, etc. shown below.
Example use:
% < /dev/urandom toprobs -n 5
0.237616281778928
0.85578479125532
0.0330049682019756
0.798812391655243
0.138499033902422
Remarks:
- I'm using
hexdump
instead ofod
because it gave me an easier way to format the output the way I wanted it; - Annoyingly though,
hexdump
does not support 64-bit integers (wtf???); - The functions' interface needs work (e.g. they should accept
-n5
as well as-n 5
), but given my pitiful shell programming skillz, this was the best I could put together quickly. (Comments/improvements welcome, as always.)
The big surprise I got from this exercise was to discover how hard it is to program on the shell the most elementary numerical stuff (e.g. read a hexadecimal float, or get the maximum native float value)...
_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
should give you integer number only.