Как получить относительный путь между двумя каталогами?

Как получить относительный путь между двумя каталогами?

Допустим, у меня есть переменная с путем 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:-.}"
}

(конец обновления)

Связанный контент