Допустим, у меня есть переменная с путем release/linux/x86
, и мне нужен относительный путь из другого каталога (например, ../../..
для текущего рабочего каталога). Как мне получить его в команде оболочки (или, возможно, GNU Make)?
Поддержка программных ссылок не требуется.
Этот вопрос был существенно изменен на основе принятого ответа для улучшения терминологии.
решение1
Совершенно не ясно, в чем его цель, но это сделает именно то, о чем просили, используяGNU-реальный путь:
realpath -m --relative-to=release/linux/x86 .
../../..
realpath -m --relative-to=release///./linux/./x86// .
../../..
решение2
Вот функция оболочки, которая возвращает относительный путь от исходного до целевого каталога, используя только манипуляцию строками — через расширение параметров оболочки — без доступа к диску или сети. Имя пути отсутствует разрешение готово.
Ожидает два параметра, source-dir и target-dir, оба абсолютные канонизированные непустые пути, любой из них может заканчиваться - /
, ни один из них не должен существовать. Возвращает результат в переменной оболочки $REPLY
как относительный путь от source-dir до target-dir без завершающего /
, .
если void.
Алгоритм взят из сообщения comp.unix.shell 2005 года, которое теперь поднялось доархив.org.
pnrelpath() {
set -- "${1%/}/" "${2%/}/" '' ## '/'-end to avoid mismatch
while [ "$1" ] && [ "$2" = "${2#"$1"}" ] ## reduce $1 to shared path
do set -- "${1%/?*/}/" "$2" "../$3" ## source/.. target ../relpath
done
REPLY="${3}${2#"$1"}" ## build result
# unless root chomp trailing '/', replace '' with '.'
[ "${REPLY#/}" ] && REPLY="${REPLY%/}" || REPLY="${REPLY:-.}"
}
Использовать как
$ pnrelpath "$HOME" "$PWD"
projects/incubator/nspreon
$ pnrelpath "$PWD" "$gimpkdir"
../../../.config/GIMP
$ pnrelpath "$PWD" "$(cd "$dirnm" && pwd || false)"
# using cd to resolve, canonicalize ${dirnm}
или, сURIделюсь scheme://authority
,
$ pnrelpath 'https://example.com/questions/123456/how-to' 'https://example.com/media'
../../../media
Обновлять2022-11-24
Пропуск while
оператора в предыдущей функции вернет то, что realpath --relative-base
делает: относительный путь от исходного к целевому каталогу, если цель находится в исходном или ниже, в противном случае абсолютный путь. Применяются аналогичные предварительные и постусловия.
pnrelbase() {
set -- "${1%/}/" "${2%/}/" ## '/'-end to avoid mismatch
REPLY="${2#"$1"}" ## build result
# unless root chomp trailing '/', replace '' with '.'
[ "${REPLY#/}" ] && REPLY="${REPLY%/}" || REPLY="${REPLY:-.}"
}
(конец обновления)