Bash’s output redirection – what’s the difference between >> and >&, redirecting and duplicating

bashio-redirectionshell-script

I'm trying to understand output redirection, but I'm struggeling. I don't think I really get the differences.

1 > file        # -  redirect stdout to file (override mode)
1 >> file       # -  redirect stdout to file (append mode)
2 > 1           # 1) would that also redirect stderr to stdout, replacing stdout?
2 >> 1          # 2) would this redirect stderr to stdout (appending to it,
                #    i.e. haivng both sent to stdout?)
1>&9            # -  duplicates stdout to file descriptor (pointer) 9 
                # 3) what's the difference of 2>&1 to a 2 >> 1? Does >> only run at the end
                #     of output?
echo foo > file # -  redirects output to file (override mode)
>file 2>&1      # -  duplicates stderr to stdout, then redirects to file in override mode 
                # 4) why is this giving me stdout, too, when the syntax is 2>&1, 
                #    i.e. duplicate stderr into stdout - not merge 2 into 1?

I'm assuming the ampersand & means duplicate, as opposed to redirect. But what's the difference of redirecting a to b (will a remain unchanged?) to duplicating a to b (will a and b be the same?)? 2>&1 effectively seems to redirect and merge 2 into 1, i.e. what would have gone into 2 is now in 1, but only in 1… why?

I'm so confused…

Best Answer

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.

Related Question