Обойдя папку /proc/self
для моей оболочки mksh
, я обнаружил странную вещь: в /proc/self/fd/*
есть все стандартные файловые дескрипторы (0 для stdin, 1 для stdout и 2 stderr), некоторые файловые дескрипторы , но также некоторые дополнительные - 24, 25, 3. И я технически могу перечислить их с глобусом в оболочке:
$ for fd in /proc/self/fd/* ; do echo $fd ; done
/proc/self/fd/0
/proc/self/fd/1
/proc/self/fd/2
/proc/self/fd/24
/proc/self/fd/25
/proc/self/fd/3
Но когда я пытаюсь stat
их или использовать find
на их, как сообщают, не существует.
$ find /proc/self/fd/*
/proc/self/fd/0
/proc/self/fd/1
/proc/self/fd/2
find: ‘/proc/self/fd/24’: No such file or directory
find: ‘/proc/self/fd/25’: No such file or directory
/proc/self/fd/3
То же самое происходит в bash
, но только с одним вспомогательным файловым дескриптором.
$ for fd in /proc/self/fd/* ; do echo $fd; done
/proc/self/fd/0
/proc/self/fd/1
/proc/self/fd/2
/proc/self/fd/255
/proc/self/fd/3
$ find /proc/self/fd/*
/proc/self/fd/0
/proc/self/fd/1
/proc/self/fd/2
find: ‘/proc/self/fd/255’: No such file or directory
/proc/self/fd/3
Вопрос: что это за дополнительные файловые дескрипторы? Какова их цель?
Зондирование /proc/self
хитрый бизнес, так как он изменяется для каждого процесса. Когда Вы делаете /proc/self/fd/*
, оболочка разворачивает подстановочный знак, таким образом, это перечисляет свои собственные дескрипторы файлов. Но когда они передаются другой команде, как find
или ls
, пути теперь будут для того процесса /proc/self
, и это может или не может иметь fds с теми числами.
Еще более хитрый, оболочка может открыть дескрипторы файлов во время подстановочного расширения.
Сравнение с /proc/$$/fd
мог бы освещать:
bash
:
$ ls -l /proc/self/fd /proc/$$/fd/* &
[1] 5172
$ lrwx------ 1 muru muru 64 Jan 1 20:16 /proc/4932/fd/0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 1 20:16 /proc/4932/fd/1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 1 20:16 /proc/4932/fd/2 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 1 20:16 /proc/4932/fd/255 -> /dev/pts/1
/proc/self/fd:
total 0
lrwx------ 1 muru muru 64 Jan 1 20:24 0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 1 20:24 1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 1 20:24 2 -> /dev/pts/1
lr-x------ 1 muru muru 64 Jan 1 20:24 3 -> /proc/5172/fd
[1]+ Done ls --color=auto -l /proc/self/fd /proc/$$/fd/*
Путем отправки его в фон я заставил удар печатать PID, и Вы видите это /proc/self/fd/3
точки к ls
'собственный /proc/<PID>/fd
, который это открыло для сканирования. Записи с 4932
, OTOH, для fds удара, и специальный - 255. Объяснение найдено в этом, ТАК отправьте:
Открытые файлы 0 (stdin), 1 (stdout), и 2 (stderr). 255 немного приема, которые колотят использование для хранения копии их для того, когда они перенаправляются. Это характерно для удара.
Источник: https://books.google.com/books? id=wWjqCF9HLfYC&pg=PA231
С mksh
:
$ ls -l /proc/self/fd /proc/$$/fd/* &
[1] 5075
$ lrwx------ 1 muru muru 64 Jan 1 20:22 /proc/5074/fd/0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 1 20:22 /proc/5074/fd/1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 1 20:22 /proc/5074/fd/10 -> /dev/tty
lrwx------ 1 muru muru 64 Jan 1 20:22 /proc/5074/fd/2 -> /dev/pts/1
/proc/self/fd:
total 0
lrwx------ 1 muru muru 64 Jan 1 20:22 0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 1 20:22 1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 1 20:22 2 -> /dev/pts/1
lr-x------ 1 muru muru 64 Jan 1 20:22 3 -> /proc/5075/fd
[1] + Done ls -l /proc/self/fd /proc/$$/fd/*
Практически то же самое, за исключением того, что дополнительный fd равняется 10, и я держал бы пари, что это по той же причине как удар, так как исходный код указывает, что fd 10 и вперед используется оболочкой.
Я не получил два или три дополнительных fds, но это могло произойти из-за любого количества вещей, происходящих во время подстановочного расширения, или из-за фоновых заданий или некоторой другой неясной причины.
Если я выполняю Ваш for
цикл, я действительно получаю эфемерный fd 3:
$ for fd in /proc/$$/fd/* ; do ls -l $fd ; done
lrwx------ 1 muru muru 64 Jan 2 17:39 /proc/6012/fd/0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 17:39 /proc/6012/fd/1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 17:39 /proc/6012/fd/2 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 17:39 /proc/6012/fd/255 -> /dev/pts/1
ls: cannot access '/proc/6012/fd/3': No such file or directory
И здесь, использование strace
прослеживать выполнение:
strace -e open -o log bash -c 'for fd in /proc/$$/fd/* ; do : ; done'
Мы будем видеть, что третий фарадей, на самом деле, /proc/<PID>/fd
:
$ tail log
open("/usr/lib/libreadline.so.7", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libdl.so.2", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/libncursesw.so.6", O_RDONLY|O_CLOEXEC) = 3
open("/dev/tty", O_RDWR|O_NONBLOCK) = 3
open("/usr/lib/locale/locale-archive", O_RDONLY|O_CLOEXEC) = 3
open("/usr/lib/gconv/gconv-modules.cache", O_RDONLY) = -1 ENOENT (No such file or directory)
open("/usr/lib/gconv/gconv-modules", O_RDONLY|O_CLOEXEC) = 3
open("/proc/9975/fd/", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
+++ exited with 0 +++
Теперь вопрос, почему привел в порядок не это шоу fd в ранее ls
тесты? Похоже, что фоновая обработка имела некоторое отношение к этому:
$ ls -l /proc/$$/fd/* &
[1] 10091
$ lrwx------ 1 muru muru 64 Jan 2 17:46 /proc/10076/fd/0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 17:46 /proc/10076/fd/1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 17:46 /proc/10076/fd/2 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 17:46 /proc/10076/fd/255 -> /dev/pts/1
[1]+ Done ls --color=auto -l /proc/self/fd /proc/$$/fd/*
$ ls -l /proc/$$/fd/*
ls: cannot access '/proc/10076/fd/3': No such file or directory
lrwx------ 1 muru muru 64 Jan 2 17:46 /proc/10076/fd/0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 17:46 /proc/10076/fd/1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 17:46 /proc/10076/fd/2 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 17:46 /proc/10076/fd/255 -> /dev/pts/1
Передний план ls
показывает пропавших без вести fd.
Теперь, снова трассировка с strace
:
strace -fe open,execve,fork -o log bash -ic 'ls -l /proc/self/fd /proc/$$/fd/* &'
Мы видим:
10731 execve("/usr/bin/bash", ["bash", "-ic", "ls -l /proc/$$/fd/* &"], [/* 67 vars */]) = 0
10731 open("/etc/ld.so.cache", O_RDONLY|O_CLOEXEC) = 3
# snip
10734 open("/proc/10731/fd/", O_RDONLY|O_NONBLOCK|O_DIRECTORY|O_CLOEXEC) = 3
10734 execve("/usr/bin/ls", ["ls", "--color=auto", "-l", "/proc/10731/fd/0", "/proc/10731/fd/1", "/proc/10731/fd/2", "/proc/10731/fd/255"], [/* 68 vars */]) = 0
Обратите внимание на изменения в PIDs. Кажется, что подстановочное расширение происходит после разветвления, но переменное расширение происходит перед этим. Так, fd 3 существует, но в другом процессе. Теперь я Вы используете self
вместо $$
, Вы будете видеть и 3 и 255:
$ strace -fe open,execve -o log bash -ic 'ls -l /proc/self/fd/* &'
[1] 10790
ls: cannot access '/proc/self/fd/255': No such file or directory
ls: cannot access '/proc/self/fd/3': No such file or directory
lrwx------ 1 muru muru 64 Jan 2 18:04 /proc/self/fd/0 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 18:04 /proc/self/fd/1 -> /dev/pts/1
lrwx------ 1 muru muru 64 Jan 2 18:04 /proc/self/fd/2 -> /dev/pts/1
Связанный ответ на сайте Unix&Linux Stackexchange цитирует ответ из почтового списка:
Fd 255 используется внутренне в качестве соединения с tty, так, чтобы это не вмешивалось в использование должностного лица для перемещения fds. Bash также выделяет высокий fds при обработке замены процесса' <(нечто)' по той же причине.
Andreas Schwab