Send in your Unix questions today! |
See additional Unix tips and tricks
There are several ways to conveniently generate random data on Unix systems. One popular way is to make use of Perl's rand function. Another is to employ the /dev/random or /dev/urandom pseudodevice to generate a string of the required length. Both tools easily produce the required data, but take a bit of finessing to get just what you need.
Perl's rand function without a parameter, for example, will generate a number between 0 and 1. You might use it like this in a script:
$random = rand();
print "$random\n";
Generated numbers might look like the numbers below. Notice that the numbers contain a variable number of digits following the decimal point.
0.0243931627800933
0.545351391515347
0.67962646484375
0.4464111328125
0.85577392578125
If you want larger numbers, you can supply an argument to the rand function. When we specify 100, for example, we generate numbers between 0 and the number provided. Using the code below, we generate numbers such as 78.1768798828125 and 10.85205078125.
$random = rand( 100 );
print "$random\n";
If you're troubled by the decimal places, you can remove them easily by sending the response from your call to rand inside a call to the int function:
$random = int( rand( 100 ) );
print "$random\n"
Using code like this, you would generate integers between 0 and 100.
27
94
If you want to generate very large numbers, you can multiply the result of rand() by 10 billion or some other large number. Alternately, you could find a way to ignore the decimal point and use the number generated. On the other hand, the /dev/random and /dev/urandom devices offer easy alternatives.
To generate a single random character using /dev/random, you would probably use a dd command such as this:
dd if=/dev/random bs=1 count=1
The /dev/random device serves as the input file and the arguments bs (blocksize) and count indicate the size and number of data chunks to be generated.
This command is going to generate unattractive output unless you send standard out to /dev/null:
$ dd if=/dev/random bs=1 count=1
q1+0 records in
1+0 records out
In the command below, we get rid of the records in and records out messages and save our data in a file.
$ dd if=/dev/random bs=1 count=16 2>/dev/null 1>randdata
$ more randdata
¥ÿÞïGöqüLµbash-2.03$ ls -l randdata
-rw-r--r-- 1 shs staff 16 May 29 10:49 randdata
If you want to generate large amounts of random data, you will probably want to adjust the blocksize. Here, we specify a block size of 1 kilobyte:
dd if=/dev/random bs=1k count=1 2>/dev/null 1>randata
Note, however, that our data will contain many unprintable characters. If you need to constrain your data to some particular format, you might use some other command in concert with /dev/random. In the command below, we use od with a -D (unsigned decimal) argument to generate only digits.
od -D -A n /dev/random | head -2
0834209578 2912364186 3486943798 2552158237
2557486046 3061961732 0050935527 1581200130
In a similar command, we can use od with a -X (hexadecimal) argument to yield string using the digits 0-9 and characters A-F.
$ od -X -A n /dev/random | head -2
a6531c80 cbc463c0 5be59fd4 ca98c680
2f96dc58 0694d8de a3952e49 b53ab86a
You can generate as much of this kind of data as you need by simply varying the number of lines you select with the head command.
The script shown below will generate hexadecimal strings up to 1024 characters in length. It makes use of an od -X command like that shown in the previous command and removes carriage returns and blank spaces to turn the generated data into a long continuous string. Scripts such as this could be useful in generating random keys for various security applications. If you need more than 1024 characters, you can increase the number of lines to more than 32 (see LINES=). However, at some point, you may request more data than the awk command near the bottom will be able to handle. If so, you can find some other way to chop the generated string down to the required length.
#!/bin/bash
LINES=32
MAX=`expr $LINES \* 32`; # max number of generated bytes
if [ $# -gt 0 ]; then
bits=$1
if [ $bits -gt $MAX ]; then
echo "ERROR: Cannot generate more than $MAX bytes"
exit 1
fi
fi
key=`od -X -A n /dev/random | head -$LINES | tr -d "\t" | tr -d " " | tr -d "\n"`
if [ $bits ]; then
echo $key | awk '{print substr($0,1,len)}' len=$bits
else
echo $key
fi