Что такое каталоги ./ и ../?

20

Простой вопрос, но я не уверен, где искать, и Google не реагирует на периоды и косые черты.

Я просто пытаюсь подсчитать количество файлов и каталогов в текущем каталоге (не включая подпапки / файлы) и пытался различить, ls -1 | wc -lи, ls | wc -lпоскольку они кажутся идентичными. Сайт, на который я смотрел, сказал: «Имейте в виду, что это также подсчет каталогов ./ и ../». ls -1Что касается одного с , и я не уверен, означает ли это, что он включает в себя каталоги ранее или что-то (что я не хочу), но, похоже, это не было сделано из-за тестирования.

Может ли кто-нибудь подтвердить, какой из них будет наиболее подходящим для подсчета количества файлов и каталогов только в текущем каталоге (не подкаталоге) и что они имеют в виду под каталогами ./ и ../?

Адам
источник
«Имейте в виду, что это также подсчет каталогов ./ и ../» неправильно (если это не опечатка для «.» И «..».
vonbrand

Ответы:

15

Каждый каталог в системе Unix (и, вероятно, в любой другой системе) содержит как минимум две записи каталога. Это .(текущий каталог) и ..(родительский каталог). В случае корневого каталога они указывают на то же место, но с любым другим каталогом они отличаются. Вы можете убедиться в этом сами, используя команды stat, pwdand cd(в Linux):

$ cd /
$ stat . .. bin sbin | grep Inode
Device: 802h/2050d      Inode: 2           Links: 27
Device: 802h/2050d      Inode: 2           Links: 27
Device: 802h/2050d      Inode: 548865      Links: 2
Device: 802h/2050d      Inode: 2670593     Links: 2
$ pwd
/
$ cd ..
$ pwd
/
$

Обратите внимание, binи у sbinкаждого есть две ссылки на него. Одна - это запись в корневом каталоге, а другая - .запись в этом каталоге.

Использование lsс конвейером в wc -l- это простой трюк для подсчета количества строк в выводе ls. Предполагается, что каждый файл или каталог будет занимать ровно одну строку в выводе. GNU ls будет, когда вывод не является терминалом, делать это автоматически; другим может понадобиться -1опция явного включения поведения. wc -lпросто считает и выводит количество строк ( -l) на своем входе.

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

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

Если вам нужно правильно обрабатывать необычные символы (в первую очередь, новые строки) в именах записей каталога, я предлагаю использовать -bопцию ls, чтобы избежать их. ls -1bAбудет печатать каждое имя записи каталога в отдельной строке, экранируя необычные символы (поэтому каждая запись каталога будет рассматриваться как единое целое), включая любые файлы точек и -директории. Выберите wc -lполную командную строку, в ls -1bA | wc -lкоторой будет указано количество файлов и каталогов в текущем каталоге (но игнорируйте .и ..; в этом разница между -aи -A), но не переходите ни в какие подкаталоги. Если вы не хотите, чтобы какие-либо точечные файлы были засчитаны в общую сумму, просто опустите -Aпараметр до ls.

CVn
источник
И то, -aи другое -Aвключает в себя скрытые файлы, которые, как я понял, я хочу избежать, так что в большинстве случаев я бы хотел ls -b | wc -l, но это дает мне правильный ответ. Неправильная ли строка, которую я скопировал и вставил относительно этой команды? Если это правильно, не должен ли я получить вывод 8, если в каталоге 6 файлов или папок?
Адам
@ Адам да, это, вероятно, поможет (ls -b | wc -l); Вы также можете использовать «-1» (тире + номер один), который вызывает перечисление в одном столбце вместо всех в одной строке, но в любом случае это происходит при передаче по конвейеру другой команде. Так что (imho) я бы оставил это как "ls -1b | wc -l"; и чтобы "проверить", запустите "ls -1b" и посчитайте количество строк, затем запустите "ls -1b | wc -l" и проверьте результаты. (Вот как отлаживать / тестировать каналы.)
Майкл,
@Sardathrion, эти часто задаваемые вопросы вводят в заблуждение. Соглашения о файловой системе Unix не являются «странными»; где они распространены, это другая система, собирающая их. Но хорошо. Затем говорится, что «команда file использует магические числа для идентификации ...», что неверно: она также использует много эвристик. Не очень надежный в моей книге.
vonbrand
@vonbrand: достаточно честно, ссылка удалена. Я просто просмотрел это, и это казалось нормальным. Я знаю, что нашел хороший, но теперь не могу вспомнить, где он был.
Сардатрион - Восстановить Монику
1
Вы ошибаетесь: . и .. являются историческими артефактами UNIX 1970-х годов и являются результатом того времени, когда еще не было mkdir()системного вызова. Не все файловые системы имеют их, и они даже не нужны и не требуются POSIX.
Шили
6

Чтобы ответить на вопрос в теме:

Когда каталог B создается в Unix, он добавляется как новая запись в другой каталог A (его родительский каталог), а в B добавляются две записи: одна называется .жесткой ссылкой на себя, а другая ..- жесткой ссылка на А.

Это единственные разрешенные жесткие ссылки на каталоги (хотя в некоторых старых версиях некоторых Unices также допускались произвольные ссылки).

вот почему в большинстве файловых систем ( btrfsчто является заметным исключением), номер linksкаталога является показателем того, сколько у него подкаталогов (учитывая их ..записи).

Когда вы переименовываете / перемещаете каталог, если он находится в том же каталоге (под другим именем), Aизменяется только запись имени в . B .и ..не влияет. Но если вы двигаетесь это сделать другой каталог, то ..в Bизменится. Это объясняет, почему вы можете переименовывать каталог, для которого у вас нет прав на запись (при условии, что у вас есть доступ на запись в родительский каталог), только если вы не перемещаете его в другой каталог (в противном случае необходимость изменить ..запись предотвращает Вы двигаете это).

Но /a/b/../cбудьте осторожны: может не совпадать с тем, /a/cчто /a/bможет быть символической ссылкой на другой каталог.

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

Чтобы подсчитать количество записей в текущем каталоге, исключая .и ..с помощью bash, вы можете сделать:

shopt -s nullglob dotglob
set -- *
echo "$#"

С зш:

f=(*(ND))
echo $#f

Портабельно:

find . ! -name . -prune -print | grep -c /
Стефан Шазелас
источник
Я немного запутался; все три из перечисленных вами добавляют один к фактическому количеству. например, если у меня есть 6 файлов или папок в каталоге, они выводят 7, а не 6. Мне кажется, что ls | wc -lэто единственный исключающий .и..
Адам
1
@ Adam, lsне показывает список скрытых файлов. Вы должны ls -Aполучить так же, как те. Если вы не хотите считать скрытые файлы, снимите dotglob(для bash) или D(для zsh) или добавьте ! -name '.*'перед -printдля find.
Стефан Шазелас
Да, я только заметил это после фактического перечисления файлов. Знаете ли вы, почему по- ls | wc -lпрежнему дает мне правильный ответ и исключает скрытые файлы, .& ..?
Адам
1
Адам, в каталоге, у вас есть ., ..и другой файл, имя которого начинается с .которой не указана Л.С. , но будет по ls -A. Так ls | wc -lчто не дает вам правильный ответ, потому что он не считает этот скрытый файл.
Стефан Шазелас
1
Да, .и ..это скрытые файлы, так как они начинаются с .. Есть даже легенда, объясняющая, что точечные файлы скрыты случайно, так как ранняя реализация lsдолжна была исключать только .и .., но была ошибка, из-за которой исключался любой файл, начинающийся с .. ls | wc -lне работает, если имена файлов содержат символы новой строки.
Стефан Шазелас
1

Я не большой эксперт по Linux, но я знаю Linux (раньше был администратором 16 лет назад, на Slackware :), доброе старое время

каталоги ./ и ../ это просто:. является текущим каталогом, .. является предыдущим каталогом (в дереве каталога pwd -local команда-

Если он их считает, я считаю, что они добавляют 2 к общему количеству листингов, на самом деле не идут рекурсивно, подсчитывают каталог ниже текущего, а также снова считают текущий каталог (.) :))

Так что в основном я думаю, что это добавляет значение 2 к количеству (файлам) в текущем каталоге.

Кто-нибудь поправит меня, если я ошибаюсь.

Я просто пишу, чтобы помочь и увидел, что никто не ответил на этот вопрос здесь, они могут быть заняты. Но просто поэкспериментируйте и посмотрите, есть ли у вас 10 файлов и получите счет 12, вот и все.

Адриан Танасе
источник
Да, Адриан прав. является текущим каталогом, а .. является каталогом выше в иерархии.
Щайба
.. не всегда ссылается на предыдущий каталог в дереве: в "/" .. также ссылается на текущий каталог.
Бонси Скотт
потому что вы можете находиться в / root файловой системы?
Адриан Танасе
Если он добавляет два к числу файлов в каталоге, почему я получаю правильный ответ при тестировании его в терминале на OSX? например, каталог с 6 файлами или папками выдаст 6, а не 8, когда я это сделаюls | wc -1
Адам
Я понял, что это потому, что они включают скрытые файлы (а именно .ds_store), но я до сих пор не понимаю, как ls | wc -lвключает .и ..когда я получаю правильный ответ, в отличие от правильного ответа + 2.
Адам