strace
показує цю послідовність системних викликів:
$ strace -o strace.log tee /proc/self/fd/{3..6} 3>&1
...
$ cat strace.log
...
openat(AT_FDCWD, "/proc/self/fd/3", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 4
openat(AT_FDCWD, "/proc/self/fd/4", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 5
openat(AT_FDCWD, "/proc/self/fd/5", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 6
openat(AT_FDCWD, "/proc/self/fd/6", O_WRONLY|O_CREAT|O_TRUNC, 0666) = 7
...
Перший рядок відкривається /proc/self/fd/3
і присвоює йому наступний доступний номер fd, 4. /proc/self/fd/3
це спеціальний шлях. Відкриваючи це, ефект, подібний до копіювання fd 3: fd 4 вказує на те саме місце, що і fd 3, tty.
Те ж саме відбувається і для кожного наступного openat()
дзвінка. Коли пил осідає fds 4, 5, 6 і 7, всі дублікати fd 3.
- 1 → тти
- 3 → тти
- 4 → тти
- 5 → тти
- 6 → тти
- 7 → тти
Зауважте, що 3>&1
перенаправлення не важливо. Важливо те, що ми просимо трійника відкрити /proc/self/fd/N
там, де N вже використовується. Ми повинні отримати той самий результат, якщо ми позбудемося 3>&1
і /proc/self/fd/2
натомість матимемо трійник . Подивимось:
$ echo foo | tee /proc/self/fd/{2..6}
foo
foo
foo
foo
foo
foo
Підтверджено! Той самий результат.
Ми також можемо повторювати одне і те ж число fd знову і знову. Ми отримуємо такий же результат, коли потрапляємо на fd 6. До того моменту, коли він досягне останнього, він відкрив достатньо дескрипторів, щоб зробити стрибок до 6 можливим.
$ echo foo | tee /proc/self/fd/{2,2,2,2,6}
foo
foo
foo
foo
foo
foo