Despite being deprecated, dd has an incredible number of uses; I honestly have no idea how I'd live without it. As the Jargon File entry says, is has no replacement.

The simplest function dd is capable of is copying one file to another.

dd if=infile of=outfile
OR,
dd < infile > outfile
because stdin and stdout are the default in and out files.

That's all well and good, but cat can handle that. Where cat is occasionally handy, though, dd is industrial strength. For example, let's extract the boot sector from a floppy disk:

dd if=/dev/fd0 of=/tmp/bootsect.img bs=512 count=1
copies the first 512 bytes of the disk to a file.

dd if=/dev/fd0 of=/tmp/bootsect.img bs=1 count=512
does it as well, but the former is one 512-byte read, whereas the latter is 512 1-byte reads. Who cares? ariels points out that some devices have native block sizes, such that any read will force at least a block to be read. For example, reads from most disk drives occur in 512 byte sectors; thus one should do reads in multiples of 512 bytes for best speed. Note that we restrict count, the number of blocks of size bs transferred, in each case; we only want the first 512 bytes. The default behavior is to go until EOF on the input file.

Now things are getting interesting. This is just the beginning, though -- dd has even more strange capabilities. Adding a skip=n option causes dd to skip the first n bytes of the input file; adding a seek=n option causes it to seek n bytes into the output file before beginning its copy. This is great for resuming a copy where it left off, or copying out a chunk of a file (for example, extracting a file in the body of an email from the headers), or piecing together a file from debris (such as lost clusters collected in /lost+found).

But wait, there's more!

dd also has a conv option, which causes it to convert between types of files. It can convert between ASCII and EBCDIC, convert files between sequential and random access (that is, between fixed-length records and newline-terminated variable length records, AKA lines), convert between lower and upper case, and swap bytes to correct the endianness of a file.

My favorite conversion, though, isn't really a conversion at all -- it's the noerror "conversion". This causes dd to ignore read and write errors and proceed anyway. I have saved numerous floppy disks, rejected by Windows, with the following command:

dd if=/dev/fd0 of=/tmp/floppy.img bs=1 conv=noerror
followed by a swap of disks and a dd in the other direction. Not perfect, but it's a real lifesaver. The files this doesn't recover can be extracted with another dd -- use less to find them, then dd them out of the image.

A word to the wise about this method: Windows does not like the disks thus created. The solution is to mount the disk in UNIX, move the files off it, reformat it, and move them back on. UNIX can handle the blank spaces left where dd skipped bad sectors; Windows barfs or freezes upon reading them. (Score one for UNIX, and another for dd!)