Дублирование действительно важная часть здесь.
Давайте посмотрим, куда идут файловые дескрипторы до перенаправления. Обычно это текущий терминал, например:
STDOUT ---> /dev/pts/1
STDERR ---> /dev/pts/1
Теперь, если мы вызываем ls -lбез перенаправления, выходные сообщения и сообщения об ошибках отправляются в мой терминал под /dev/pts/1.
Если мы сначала перенаправим STDOUTфайл ( ls -l > dirlist), он будет выглядеть так:
STDOUT ---> /home/bon/dirlist
STDERR ---> /dev/pts/1
Когда мы затем перенаправить STDERRк дубликату из STDOUTфайлового дескриптора «S ( ls -l > dirlist 2>&1), STDERRидет к дубликату /home/bon/dirlist:
STDOUT ---> /home/bon/dirlist
STDERR ---> /home/bon/dirlist
Если мы сначала перенаправим STDERRна дубликат STDOUTдескриптора файла ( ls -l 2>&1):
STDOUT ---> /dev/pts/1
STDERR ---> /dev/pts/1
а затем STDOUT в файл ( ls -l 2>&1 > dirlist), мы получили бы это:
STDOUT ---> /home/bon/dirlist
STDERR ---> /dev/pts/1
Здесь STDERRвсе еще идет в терминал.
Видите ли, порядок на странице руководства правильный.
Тестирование перенаправления
Теперь вы можете проверить это сами. Используя ls -l /proc/$$/fd/, вы видите, куда STDOUT(с fd 1) и STDERR(с fd 2) идут текущие процессы:
$ 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
Давайте создадим небольшой сценарий оболочки, который показывает, куда указываются ваши файловые дескрипторы. Таким образом, мы всегда получаем состояние при вызове ls, включая любое перенаправление из вызывающей оболочки.
$ cat > lookfd.sh
#!/bin/sh
ls -l /proc/$$/fd/
^D
$ chmod +x lookfd.sh
(С помощью CtrlDвы отправляете конец файла и прекращаете catчтение команды STDIN.)
Теперь вызовите этот скрипт с различными комбинациями перенаправления:
$ ./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
Вы можете видеть, что файловые дескрипторы 1 (для STDOUT) и 2 (для STDERR) различаются. Ради интереса вы также можете перенаправить STDINи посмотреть результат:
$ ./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
(Вопрос, оставленный читателю: где дескриптор файла 255 указывает? ;-))