Two other famous special devices, /dev/random and /dev/urandom, are best discussed in tandem with the next bit of redirection: input redirection.
Input normally comes from your keyboard, passed through by the Terminal to the command. The easiest example for this is the read command: it reads from stdin until it encounters a newline (when the Enter key is pressed) and then saves the input to the REPLY variable (or anything custom, should you have given that argument). It looks a bit like this:
reader@ubuntu:~$ read -p "Type something: " answer
Type something: Something
reader@ubuntu:~$ echo ${answer}
something
Easy. Now, let's say we run this command non-interactively, which means we cannot use a keyboard and Terminal to supply the information (not a real use case for read, but this makes for a nice example).
In this case, we can use input redirection (of stdin) to supply the input to read. This is achieved with the < character, which is shorthand for <0. Remember that the stdin file descriptor was /dev/fd/0? Not a coincidence.
Let's use read in a non-interactive manner by redirecting stdin to read from a file, instead of the Terminal:
reader@ubuntu:/tmp$ echo "Something else" > answer-file
reader@ubuntu:/tmp$ read -p "Type something: " new_answer < answer-file
reader@ubuntu:/tmp$ echo ${new_answer}
Something else
To show that we're not cheating and reusing the already stored answer in the ${answer} variable, we've renamed the variable in which the reply for read is stored to ${new_answer}.
Now, at the end of the command we redirected stdin from the answer-file file, which we created first using echo + redirection of stdout. This was as simple as adding < answer-file after the command.
This redirection makes read read from the file until a newline is encountered (which is conveniently what echo always ends a string with).
Now that the basics of input redirection should be clear, let's get back to our special devices: /dev/random and /dev/urandom. These two special files are pseudo-random number generators, which is a complicated word for something that generates almost random data.
In the case of these special devices, they gather entropy (a complicated word for something like randomness) from things like device drivers, mouse movements, and other things that are mostly random.
There is a slight difference between /dev/random and /dev/urandom: when there is not enough entropy in the system, /dev/random stops generating random output, while /dev/urandom keeps going.
If you really need full entropy, /dev/random might be the better choice (in all honesty, you're probably taking other measures in that situation anyway), but most often, /dev/urandom is the better choice in your scripting, since blocking can create incredible wait times. This comes from first-hand experience and can be very inconvenient!
For our examples, we'll only show /dev/urandom; output from /dev/random is similar.
In practice, /dev/urandom spits out bytes randomly. While some bytes are in the printable ASCII character range (1-9, a-z, A-Z), others are used for whitespaces (0x20) or newlines (0x0A).
You can see the randomness by using head -1 to grab 'the first line' from /dev/urandom. Since a line is terminated by a newline, the command head -1 /dev/urandom will print everything until the first newline: this can be a few or a lot of characters:
reader@ubuntu:/tmp$ head -1 /dev/urandom
~d=G1���RB�Ҫ��"@
F��OJ2�%�=�8�#,�t�7���M���s��Oѵ�w��k�qݙ����W��E�h��Q"x8��l�d��P�,�.:�m�[Lb/A�J�ő�M�o�v��
�
reader@ubuntu:/tmp$ head -1 /dev/urandom
��o�u���'��+�)T�M���K�K����Y��G�g".!{R^d8L��s5c*�.đ�
The first instance we ran printed a lot more characters (not all of them readable) than the second time around; this can be directly linked to the randomness of the bytes generated. The second time we ran head -1 /dev/urandom, we encountered the newline byte, 0x0A, faster than the first iteration.