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