A duplicação é realmente a parte importante aqui.
Vamos ver para onde os descritores de arquivo estão indo antes do redirecionamento. Normalmente, este é o terminal atual, por exemplo:
STDOUT ---> /dev/pts/1
STDERR ---> /dev/pts/1
Agora, se ligarmos ls -lsem redirecionamento, as mensagens de saída e de erro vão para o meu terminal em /dev/pts/1.
Se primeiro redirecionarmos STDOUTpara um arquivo ( ls -l > dirlist), será assim:
STDOUT ---> /home/bon/dirlist
STDERR ---> /dev/pts/1
Quando , em seguida, redirecionar STDERRa um duplicado de STDOUTdescritor de arquivo 's ( ls -l > dirlist 2>&1), STDERRvai para uma cópia de /home/bon/dirlist:
STDOUT ---> /home/bon/dirlist
STDERR ---> /home/bon/dirlist
Se primeiro redirecionarmos STDERRpara uma duplicata do STDOUTdescritor de arquivo ( ls -l 2>&1):
STDOUT ---> /dev/pts/1
STDERR ---> /dev/pts/1
e depois STDOUT para um arquivo ( ls -l 2>&1 > dirlist), teríamos o seguinte:
STDOUT ---> /home/bon/dirlist
STDERR ---> /dev/pts/1
Aqui, STDERR ainda está indo para o terminal.
Veja bem, a ordem na página de manual está correta.
Redirecionando testes
Agora, você pode testar isso sozinho. Usando ls -l /proc/$$/fd/, você vê onde STDOUT(com fd 1) e STDERR(com fd 2) estão indo para o processo atual:
$ 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
Vamos criar um pequeno script de shell que mostre para onde os descritores de arquivos estão apontados. Dessa forma, sempre obtemos o estado ao chamar ls, incluindo qualquer redirecionamento do shell de chamada.
$ cat > lookfd.sh
#!/bin/sh
ls -l /proc/$$/fd/
^D
$ chmod +x lookfd.sh
(Com CtrlD, você envia um final de arquivo e, portanto, interrompe a catleitura do comando STDIN.)
Agora, chame esse script com combinações variadas de redirecionamento:
$ ./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
Você pode ver que os descritores de arquivo 1 (para STDOUT) e 2 (para STDERR) variam. Por diversão, você também pode redirecionar STDINe ver o resultado:
$ ./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
(Pergunta deixada ao leitor: Onde o descritor de arquivos 255 aponta? ;-))