Дублирование действительно важная часть здесь.
Давайте посмотрим, куда идут файловые дескрипторы до перенаправления. Обычно это текущий терминал, например:
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 указывает? ;-))