Этот другой ответ упоминает stat . Давайте улучшим подход:
a="$(stat --format=%d:%i -- "$(pwd)/expected-subdir/")" || printf "Error A\n" >&2
b="$(stat --format=%d:%i -- "$VARIABLE_PATH/expected-subdir/")" || printf "Error B\n" >&2
[ "$a" = "$b" ] || printf "Not the same path.\n" >&2
Заметки:
- Мы используем
stat --format= , поэтому дальнейший анализ не требуется.
%d - номер устройства, %i - номер индекса. Одного последнего недостаточно, потому что два объекта на разных устройствах (файловых системах) могут иметь один и тот же номер инода.
- Оболочка достаточно умна, чтобы отдельно обрабатывать кавычки внутри и снаружи
$( ) .
printf -s - просто заглушки для обработки ошибок. В реальном сценарии вы, вероятно, захотите что-то вроде
[ "$a" = "$b" ] || { printf "Not the same path.\n" >&2; exit 2; }
Несуществующий путь заставит stat выдать ошибку.
- Конечные косые черты важны. Если
foo является символической ссылкой на каталог, stat foo будет проверять символическую ссылку, а stat foo/ будет проверять каталог. Альтернативно stat -L и используйте это возможно.
-- в случае, если $(pwd) или $VARIABLE_PATH начинаются с - (см. правило 10 здесь ).
Есть утилиты readlink -f (также упомянутые в другом ответе) и утилиты realpath . Один из них может быть лучшим подходом, чем stat . Это зависит от того, какие аспекты путей важны для вас. Основные отличия:
- Если
/foo/bar/ является привязкой к /moo/baz/ то stat --format=%d:%i скажу вам, что они одинаковые, но readlink или realpath будут считать их разными.
- Ситуация осложняется с символическими ссылками и
.. Смотрите man 1 realpath, особенно параметры -L и -P .
При использовании символических ссылок, если ваш скрипт изменяет каталог вверх (в сторону / , например, cd ..), вы можете получить разные результаты в зависимости от того, с чего начинаете, даже если stat или readlink -f говорят, что две начальные точки совпадают (сравните Почему ls .. показывает реальный родительский контент, когда я нахожусь в каталоге символических ссылок?). Рассмотрим этот подход:
# early in the script
set -P
cd . # seems like no-op but updates the PWD variable to physical path
При использовании bind mounts, если ваш скрипт меняет каталог, вы можете получить разные результаты в зависимости от того, с чего начинаете, даже если stat говорит, что две начальные точки совпадают. Рассмотрим пример с /foo/bar/ и /moo/baz/ (уже представлен выше). Очевидно, что /foo/ может полностью отличаться от /moo/ . Но также /foo/bar/abc может отличаться от /moo/baz/abc потому что любой abc может быть независимой привязкой к чему-то другому. Так что не только cd .. может поставить вас в другое место, но и cd abc .
Ну, abc может быть файлом. Что делать, если вы связываете другой файл с /moo/baz/abc но не с /foo/bar/abc? Воспринимаемые файлы будут отличаться, даже если stat говорит, что вы в одном месте!
Из-за этих проблем вы можете предпочесть readlink или realpath stat .
stat , readlink и realpath не требуются POSIX. В вашем случае портативное решение может выглядеть так:
a="$(cd -P -- "expected-subdir" && pwd -P)" || exit 1
b="$(cd -P -- "$VARIABLE_PATH/expected-subdir" && pwd -P)" || exit 1
[ "$a" = "$b" ] || { printf "Not the same path.\n" >&2; exit 2; }
Он работает с помощью cd -ing к любому пути и извлекает его с помощью pwd . Эти операции явно вынуждены действовать "физически" (-P).
set -P не является POSIX. Если вы хотите, чтобы оболочка POSIX "эмулировала" set -P , замените cd и pwd:
cd() { command cd -P "$@"; }
pwd() { command pwd -P "$@"; }
POSIX требует, чтобы последний параметр -P или -L вступил в силу, поэтому pwd -L прежнему извлекает логический путь, даже если функция "внедряет" -P ; то же самое для cd -L .