Как получить полный PATH, * разрешающий * для символических ссылок

Я написал сценарии bash, которые принимают имя каталога в качестве аргумента. Одна точка ('.') Является допустимым именем каталога, но мне иногда нужно знать, где '.' является. readlink а также realpath Команды предоставляют разрешенный путь, который не помогает, потому что мне нужно разрешить символические ссылки.

Например, разрешенный путь к данному каталогу может быть что-то вроде /mnt/vol_01/and/then/someтогда как скрипт вызывается с помощью "." где '.' является /app/then/some (Сим-ссылка, которая будет разрешена на первый путь, который я дал).

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

Упрощенный пример скрипта:

DEST_DIR=$1

# Convert the given destination directory to a full path, ALLOWING 
# for symbolic links.  This is necessary in cases where '.' is 
# given as the destination directory.
DEST_DIR=$(cd $DEST_DIR && pwd -L)

# Do stuff in $DEST_DIR

Мой вопрос: мое использование cd а также pwd лучший способ получить то, что я хочу? Или есть лучший способ?

1 ответ

Решение

Если все, что вы хотите сделать, это создать абсолютный путь, который имеет минимальные изменения относительно относительного пути, то простой, безопасный и быстрый путь к нему:

[[ $dest_dir == /* ]] || dest_dir=$PWD/$dest_dir

(См. Правильное использование заглавных букв в сценариях Bash и shell для объяснения причин dest_dir предпочтительнее DEST_DIR.)

Приведенный выше код будет работать, даже если каталог не существует (пока) или если невозможно cd к нему (например, потому что его разрешения не позволяют это). Может создавать пути с избыточным '.' компоненты, компоненты.. и избыточные слэши (`/a//b', '//a/b/', ...).

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

dest_dir=$(cd -- "$dest_dir"/ && pwd)
  • -- необходимо обрабатывать имена каталогов, которые начинаются с '-'.
  • Цитаты в "$dest_dir" необходимы для обработки имен, которые содержат пробелы (на самом деле $IFS символы) или глобус символов.
  • Конечный слеш на "$dest_dir"/ необходимо обрабатывать каталог, относительное имя которого просто -,
  • гладкий pwd достаточно, потому что он ведет себя так, как будто -L был указан по умолчанию.

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

Обратите внимание, что $(cd ...) создаст подоболочку с Bash. Это хорошо с одной стороны, потому что нет необходимости cd впоследствии вернитесь в начальный каталог (что может быть невозможно), но это может вызвать проблемы с производительностью, если вы делаете это много (например, в цикле).

Наконец, обратите внимание, что код не будет работать, если имя каталога содержит одну или несколько завершающих строк новой строки (например, созданных mkdir $'dir\n'). Можно решить проблему (если вы действительно заботитесь об этом), но это грязно. См. Как избежать подстановки команд bash для удаления символа новой строки? и shell: оставляйте завершающие символы новой строки ('\n') в подстановке команд. Один из возможных способов сделать это:

dest_dir=$(cd -- "$dest_dir"/ && printf '%s.' "$PWD")    # Add a trailing '.'
dest_dir=${dest_dir%.}                                   # Remove the trailing '.'
Другие вопросы по тегам