Это нормально, что find отображает двойной слэш?

Вопрос или проблема

Это баг, что когда я использую find ./path/here/, я получаю:

./path/here//foo
./path/here//bar

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

Технически, это баг, потому что POSIX утверждает, что

все пути к другим файлам, встречающимся в иерархии, должны состоять из конкатенации текущего операнда пути, <слэша> , если текущий операнд пути не заканчивался на него, и имени файла относительно операнда пути

Но двойной слэш не имеет значения, поэтому ./path/here//foo и ./path/here/foo всегда один и тот же файл. (Двойной слэш имеет значение, если он в начале пути на нескольких вариантах Unix. Если у вас так, то надеюсь, что find обрабатывает этот случай особо.)

Для справки, одной из причин, по которой кто-то может использовать find some/dir/ вместо find some/dir, является ситуация, когда some/dir на самом деле является символической ссылкой на каталог, и вам нужно, чтобы find находил файлы в каталоге, на который указывает эта ссылка.

Но в этом случае есть лучший вариант:

find -H some/dir

-H — это опция, поддерживаемая несколькими POSIX-утилитами (ls, cp, chmod…), которая говорит утилите следовать символическим ссылкам, переданным в качестве аргументов (и только им, не путать с -L/-follow, который заставляет find следовать каждой символической ссылке, как переданным в аргументах, так и найденным во время обхода каталога).

Это все еще не функционально эквивалентно find some/dir/ в случае, когда some/dir на самом деле не каталог. В этом случае, find some/dir/ завершается с ошибкой Не является каталогом, в то время как find -H some/dir выведет этот файл, не являющийся каталогом.

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

https://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap03.html#tag_03_266

3.266 Путь:
Строка символов, используемая для идентификации файла. В контексте IEEE Std 1003.1-2001 путь состоит из, максимум, {PATH_MAX} байт, включая завершающий нулевой байт. Он имеет опциональный начальный слэш, за которым следует ноль или более имен файлов, разделенных слэшами. Путь может содержать опционально один или более завершающих слэшей. Несколько последовательных слэшей считаются теми же, что и один слэш.

Хотя это не вся картина.

https://pubs.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap04.html#tag_04_11

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

Таким образом, любой путь, который начинается ровно с 2 слэшей, //, может интерпретироваться иначе, чем путь, начинающийся с одного слэша; хотя пути, начинающиеся с 3 или более слэшей, должны вести себя так, как будто они начинаются с одного слэша.

С точки зрения POSIX, нет ожидания, что путь будет “нормализован” для удаления нескольких последовательных слэшей, и это нарушит разрешение пути на любой ОС, которая решит интерпретировать пути с префиксом // иначе, чем пути с префиксом /.

Хотя может показаться неэстетичным оставлять несколько слэшей в пути с точки зрения пользовательского вывода, любое манипулирование путем должно обрабатываться с осторожностью, чтобы избежать нарушения 4.11.

Ответ или решение

Абсолютно нормально, что команда find отображает пути с двойным символом /, как в вашем случае с find ./path/here/. Такой вывод может казаться неожиданным, но он не противоречит спецификации POSIX и не является багом. В этом ответе я подробно объясню, почему это происходит, почему это не проблема и как с этим работать.

Теория

Согласно стандарту POSIX, путь файла — это строка символов, которая используется для идентификации файла. В спецификации допускается наличие нескольких последовательных символов / в пути, и они обрабатываются как один символ. Это означает, что ./path/here//foo интерпретируется как ./path/here/foo, и оба пути указывают на одно и то же место.

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

Пример

Представьте, что вы используете команду find для поиска файлов в UNIX-подобной системе. В вашей терминальной сессии вы вводите:

find ./path/here/

И видите вывод:

./path/here//foo
./path/here//bar

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

Применение

Теперь поговорим о практическом использовании и почему это не является проблемой. Если вы используете find some/dir/, это чаще всего происходит из-за автодополнения или личной привычки. При автозаполнении командой Tab оболочка может оставлять конечный слэш, и это вполне допустимо. Даже если вы добавите слэш вручную, это не вызовет ошибок — ваша команда будет работать, как и ожидалось.

Одним из практических применений подобной записи является обработка символьных ссылок. Если some/dir является символьной ссылкой на директорию, то запись find some/dir/ будет полезна, чтобы заставить find работать непосредственно в целевой директории, а не пытаться обработать файл-ссылку. Альтернативный вариант — использование опции -H, чтобы указать find следовать за символьной ссылкой:

find -H some/dir

Этот способ позволяет более явно контролировать поведение программы с символьными ссылками. Тем не менее, важно понимать различия. Например, если some/dir не является директорией, find some/dir/ выдаст ошибку "Not a directory", тогда как find -H some/dir просто перечислит содержимое указанного файла.

Заключение

Хотя наличие двойных слэшей может показаться проблемой с точки зрения эстетики и правильности, это совершенно нормально с точки зрения функциональности и совместимости с POSIX. На практике это никак не влияет на работу и не вызывает ошибок. Если вы хотите более четко контролировать вводимые в командной строке пути, стоит использовать опции команд (например, -H) и учитывать возможные специфику используемых вами систем. Важно только помнить, что попытки нормализовать пути, удаляя излишние слэши, могут привести к проблемам на специфических UNIX-системах, где некоторые формы записи интерпретируются по-особенному.

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

Оцените материал
Добавить комментарий

Капча загружается...