Почему списки каталогов содержат текущий (.) и родительский (..) каталоги?

Всякий раз, когда я перечисляю содержимое каталога с помощью такой функции, как readdir, возвращаемые имена файлов также включают «.» и "..". У меня есть подозрение, что это просто обычные ссылки в файловой системе и поэтому неотличимы от реальных файлов, но мне всегда приходится их отфильтровывать, потому что они не являются реальными объектами в каталоге, который я перечисляю. Есть ли веская причина для таких функций, как readdir, включать их? Содержат ли некоторые операционные или файловые системы больше или разные имена виртуальных файлов? Есть ли лучший способ отфильтровать их, кроме как путем сравнения строк с "." и ".."?

Обновление: спасибо всем за ответы. Полагаю, я всегда думал, что такие вещи, как ./ и ../, были простыми соглашениями, которые можно было обрабатывать с помощью поиска и замены. Я нахожу это немного удивительным, хотя, вероятно, более эффективным и прозрачным, чтобы они были частью самой файловой системы.

Однако остается один вопрос: поскольку . и.. произвольны ли имена этих ссылок, существуют ли файловые системы, использующие другие?


person Lemming    schedule 27.11.2008    source источник


Ответы (8)


. и .. на самом деле являются жесткими ссылками в файловых системах. Они нужны для того, чтобы можно было указывать относительные пути, основываясь на каком-то эталонном пути (рассмотрим "../sibling/file.txt"). Поскольку эти жесткие ссылки действительно существуют в файловой системе, readdir имеет смысл рассказать вам о них. (на самом деле термин hard link просто означает какое-то имя, неотличимое от фактического каталога, на который ссылаются: они оба указывают на один и тот же inode в файловой системе).

Лучше всего просто strcmp и игнорировать их, если вы не хотите их перечислять.

person Johannes Schaub - litb    schedule 27.11.2008
comment
ну просто странно - person Sapphire_Brick; 06.05.2020

Первоначально это были жесткие ссылки, а количество особых случаев в коде файловой системы для . и.. были минимальными. Однако это верно не для всех современных файловых систем.

Но соглашения были установлены таким образом, что даже файловые системы, в которых эти две записи каталога фактически не существуют, все равно сообщают о своем существовании через API, такие как readdir. Изменение этого сейчас приведет к поломке большого количества кода.

person Darron    schedule 27.11.2008

У меня есть подозрение, что это просто обычные ссылки в файловой системе и поэтому неотличимы от реальных файлов.

Они есть. Хотя вы можете воспринимать файловую систему как иерархию «папок», «содержащих» папки, на самом деле это двусвязное дерево1, в котором каталоги являются узлами, а файлы — листьями. Итак, . и .. необходимы ссылки для доступа к листьям текущего узла и для обхода дерева, и это то же самое, что и все остальные ссылки.

Когда вы вызываете readdir, вы получаете все места, куда вы можете перейти напрямую из текущего узла. Если вы не хотите перечислять места, которые вы воспринимаете как «наверху», вам придется разобраться с ними самостоятельно. Вы должны написать для этого небольшую функцию, возможно, называемую readdir_down. Я не знаю, в каком порядке readdir перечисляет каталоги, но, возможно, вы можете просто выбросить первые две записи.

1) это первое приближение, также возможны "жесткие ссылки", которые делают дерево на самом деле сетью.

person Svante    schedule 27.11.2008

Одна из причин заключается в том, что без них нет возможности добраться до родительского каталога. Или получить дескриптор текущего каталога.

Без них мы не можем делать такие вещи, как:

./run_this

Действительно, мы не могли добавить '.' к $PATH, что означает, что мы никогда не сможем выполнять файлы, которых еще нет в пути.

person Matthew Schinckel    schedule 27.11.2008
comment
В Windows . кажется неявной частью PATH, то есть вы можете просто ввести run_this. Привыкнув к этому, я всегда находил использование префикса ./ немного раздражающим при использовании Linux, хотя я понимаю его значение для безопасности. - person Lemming; 27.11.2008
comment
Я особо не задумывался об ограничениях безопасности, пока мне не объяснили это ранее в этом году. Неприятный пользователь может иметь команду в своем каталоге с именем ls, которую администратор может выполнить при переходе в этот каталог, и эта команда может затем предоставить пользователю дополнительный доступ. Плохой. - person Matthew Schinckel; 11.12.2008

Это обычные каталоги, это «жесткие ссылки» на текущий каталог и каталог выше. Они присутствуют во всех каталогах (даже на корневом уровне, где .. точно такое же, как .).

При использовании ls вы можете отфильтровать . и .. с помощью ls -A (обратите внимание на заглавную -A).

При применении команды ко всем точечным файлам, но не . или .., я часто использую .??*, который соответствует только точечному файлу с именем из трех символов и более.

touch .??*

Обратите внимание, что этот шаблон также исключает любой другой файл, который начинается с точки и имеет длину всего два символа (например, .x), но такие файлы встречаются редко.

При использовании программных списков файлов, таких как readdir(), мне приходится вручную исключать . и ... Поскольку эти два файла должны быть первыми в списке, возвращаемом readdir(), вы можете сделать это:

@files = readdir(DIR);
for (1..2) { shift @files; } # get rid of . and ..
# go on with your business
person Bill Karwin    schedule 27.11.2008
comment
Эти две строки должны быть помещены в функцию. - person Svante; 27.11.2008
comment
Откуда вы знаете, что они не в функции? :-) - person Bill Karwin; 27.11.2008
comment
Как ни странно, в Windows корневые каталоги (c:\, d:\, ...) не содержат ни одной из двух ссылок. Опуская .., можно было бы иметь некоторый смысл, опуская . не. - person Lemming; 27.11.2008
comment
Билл, см. мой комментарий как да, и ..., не как да, но .... - person Svante; 27.11.2008
comment
.. в корневом каталоге файловой системы — это особый случай, по крайней мере, для файловых систем, смонтированных внутри других файловых систем. Например. если /home имеет собственную файловую систему, путь /home/.. ссылается на родительскую файловую систему, даже если фактическая запись каталога .. имеет тот же индекс, что и . - person MSalters; 06.01.2016

О них сообщается, потому что они хранятся в списке каталогов. Так всегда работали unices.

person Leon Timmermans    schedule 27.11.2008

Потому что в Unix-подобных операционных системах команды вывода списка каталогов включают их, и вы используете их для перемещения вверх и вниз по иерархии файловой системы.

Что-то вроде grep { not /^.{1,2}\z/ } readdir HANDLE должно вам подойти.

person Adam Jaskiewicz    schedule 27.11.2008
comment
На самом деле строка grep будет /^\.{1,2}$/, так как точка должна быть экранирована. Я бы, наверное, написал это как /^\.\.?$/. - person Lara Dougan; 03.01.2009

нет веских причин, по которым сканирование каталога должно возвращать эти имена файлов.

person Scott Evernden    schedule 27.11.2008
comment
Есть все причины, по которым сканирование каталога должно возвращать эти имена файлов. Как еще написать getcwd()? - person Jonathan Leffler; 27.11.2008
comment
Согласованный. Без . и .., вы не можете получить дескриптор текущего или родительского каталога. - person Matthew Schinckel; 11.12.2008
comment
Хотя я не понимаю этого аргумента. Мне уже нужно знать текущий каталог, чтобы получить его . запись в первую очередь... - person Lemming; 15.12.2008
comment
Лемминг, вы этого не сделаете, потому что вы можете использовать readdir(.), который дает вам текущий каталог. - person max; 28.01.2009