3> & 1 означает 4> & 3 5> & 3 и т. Д.?

31

Я бы ожидал

echo foo | tee /proc/self/fd/{3..6} 3>&1

потерпеть неудачу с ошибками типа / proc / self / fd / 4: нет такого файла или каталога и т. д., но, к моему удивлению, он выводит

foo
foo
foo
foo
foo

Это как будто 3>&1все последующие дескрипторы перенаправляются на стандартный вывод, за исключением того, что он не работает, если я перехожу 3на что-то другое, например

$ echo foo | tee /proc/self/fd/{3..6} 4>&1
tee: /proc/self/fd/3: No such file or directory
tee: /proc/self/fd/5: No such file or directory
tee: /proc/self/fd/6: No such file or directory
foo
foo
$ echo foo | tee /proc/self/fd/{4..6} 4>&1
tee: /proc/self/fd/5: No such file or directory
tee: /proc/self/fd/6: No such file or directory
foo
foo

Есть ли объяснение этому поведению?

Огуз Исмаил
источник

Ответы:

31

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()вызова. Когда пыль оседает, 4, 5, 6 и 7 являются дубликатами 3.

  • 1 → tty
  • 3 → tty
  • 4 → tty
  • 5 → tty
  • 6 → tty
  • 7 → tty

Обратите внимание, что 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 6. К тому времени, когда он достигает последнего, он открыл достаточно дескрипторов, чтобы сделать возможным переход к 6.

$ echo foo | tee /proc/self/fd/{2,2,2,2,6}
foo
foo
foo
foo
foo
foo
Джон Кугельман
источник