bash's output redirection - what's the difference between >> and >&, redirecting and duplicating?

First, anything after > or >> is a file name; so > 1 writes to a file named 1.

Numbers in the other forms given in your example are file descriptors. By default, programs start with file descriptors 0 (standard input), 1 (standard output) and 2 (standard error) connected; when you start a program from an interactive shell, these are connected to the terminal's input and output (you can see these by running ls -l /proc/$$/fd on Linux).

Specifying a number before >, >> or >& specifies the file descriptor you wish to manipulate; the number has to be right in front of the > symbol. Thus

echo Example 2> stderr

will print "Example" and create an empty stderr file (which would contain anything sent to the standard error).

You can think of file descriptors as entries in a table, pointing to files; thus by default:

  • 0 points to /dev/tty
  • 1 points to /dev/tty
  • 2 points to /dev/tty

Specifying 1> file (or simply > file) updates file descriptor 1 to point to file, opened in truncating mode (so its contents are replaced). Specifying 2> 1 updates file descriptor 2 to point to a file named 1, opened in truncating mode.

Duplicating file descriptors using >& (or &>, which is the preferred form) simply updates one file descriptor to point to whatever the other is pointing at. In your last example, > file updates file descriptor 1:

  • 0 points to /dev/tty
  • 1 points to file
  • 2 points to /dev/tty

and then 2>&1 updates file descriptor 2:

  • 0 points to /dev/tty
  • 1 points to file
  • 2 points to file

(order is significant: > file 2>&1 produces the above, 2>&1 > file would only end up redirecting file descriptor 1).

The 1>&9 form only works if file descriptor 9 has been opened, e.g. by copying file descriptor 1 to it (9>&1) or by opening a file (9> file). This type of construct can be useful to keep track of the original contents of file descriptors when redirecting; thus in a script you could copy 1 and 2 safely away, redirect standard output and error for whatever purpose you need, and then restore them...

The Bash manual has all the details.