Duplication is really the important part here.
Let's see where the file descriptors are going to before redirection. This is normally the current terminal, e.g.:
STDOUT ---> /dev/pts/1
STDERR ---> /dev/pts/1
Now, if we call ls -l
without redirection, output and error messages go to my terminal under /dev/pts/1
.
If we first redirect the STDOUT
to a file (ls -l > dirlist
), it looks like this:
STDOUT ---> /home/bon/dirlist
STDERR ---> /dev/pts/1
When we then redirect STDERR
to a duplicate of STDOUT
's file descriptor (ls -l > dirlist 2>&1
), STDERR
goes to a duplicate of /home/bon/dirlist
:
STDOUT ---> /home/bon/dirlist
STDERR ---> /home/bon/dirlist
If we would first redirect STDERR
to a duplicate of STDOUT
's file descriptor (ls -l 2>&1
):
STDOUT ---> /dev/pts/1
STDERR ---> /dev/pts/1
and then STDOUT
to a file (ls -l 2>&1 > dirlist
), we would get this:
STDOUT ---> /home/bon/dirlist
STDERR ---> /dev/pts/1
Here, STDERR
is still going to the terminal.
You see, the order in the man page is correct.
Testing Redirection
Now, you can test that yourself. Using ls -l /proc/$$/fd/
, you see where STDOUT
(with fd 1) and STDERR
(with fd 2), are going for the current process:
$ ls -l /proc/$$/fd/
total 0
lrwx------ 1 bon bon 64 Jul 24 18:19 0 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 18:19 1 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 07:41 2 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 18:19 255 -> /dev/pts/1
Let's create a small shell script that shows where your file descriptors are pointed. This way, we always get the state when calling ls
, including any redirection from the calling shell.
$ cat > lookfd.sh
#!/bin/sh
ls -l /proc/$$/fd/
^D
$ chmod +x lookfd.sh
(With CtrlD, you send an end-of-file and so stop the cat
command reading from STDIN
.)
Now, call this script with varying combinations of redirection:
$ ./lookfd.sh
total 0
lrwx------ 1 bon bon 64 Jul 24 19:08 0 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 19:08 1 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 19:08 2 -> /dev/pts/1
lr-x------ 1 bon bon 64 Jul 24 19:08 255 -> /home/bon/lookfd.sh
$ ./lookfd.sh > foo.out
$ cat foo.out
total 0
lrwx------ 1 bon bon 64 Jul 24 19:10 0 -> /dev/pts/1
l-wx------ 1 bon bon 64 Jul 24 19:10 1 -> /home/bon/foo.out
lrwx------ 1 bon bon 64 Jul 24 19:10 2 -> /dev/pts/1
lr-x------ 1 bon bon 64 Jul 24 19:10 255 -> /home/bon/lookfd.sh
$ ./lookfd.sh 2>&1 > foo.out
$ cat foo.out
total 0
lrwx------ 1 bon bon 64 Jul 24 19:10 0 -> /dev/pts/1
l-wx------ 1 bon bon 64 Jul 24 19:10 1 -> /home/bon/foo.out
lrwx------ 1 bon bon 64 Jul 24 19:10 2 -> /dev/pts/1
lr-x------ 1 bon bon 64 Jul 24 19:10 255 -> /home/bon/lookfd.sh
$ ./lookfd.sh > foo.out 2>&1
$ cat foo.out
total 0
lrwx------ 1 bon bon 64 Jul 24 19:11 0 -> /dev/pts/1
l-wx------ 1 bon bon 64 Jul 24 19:11 1 -> /home/bon/foo.out
l-wx------ 1 bon bon 64 Jul 24 19:11 2 -> /home/bon/foo.out
lr-x------ 1 bon bon 64 Jul 24 19:11 255 -> /home/bon/lookfd.sh
You can see, that the file descriptors 1 (for STDOUT
) and 2 (for STDERR
) vary. For fun, you could also redirect STDIN
and see the result:
$ ./lookfd.sh < /dev/zero
total 0
lr-x------ 1 bon bon 64 Jul 24 19:18 0 -> /dev/zero
lrwx------ 1 bon bon 64 Jul 24 19:18 1 -> /dev/pts/1
lrwx------ 1 bon bon 64 Jul 24 19:18 2 -> /dev/pts/1
lr-x------ 1 bon bon 64 Jul 24 19:18 255 -> /home/bon/lookfd.sh
(Question left to the reader: Where does file descriptor 255 point? ;-))
a = 1; b = a; a = 2
you expecta == 2 && b == 1
to be true. The redirection2>&1
is similar to theb = a
assignment - it is by value, not by reference.2>&1
does not wed file descriptor 2 to file descriptor 1 for all of eternity - they are still 2 distinct file descriptors, who happen to point to the same file.