Como obter o caminho relativo entre dois diretórios?

Como obter o caminho relativo entre dois diretórios?

Digamos que eu tenha uma variável com path release/linux/x86e queira o caminho relativo de um diretório diferente (ou seja, ../../..para o diretório de trabalho atual), como eu conseguiria isso em um comando shell (ou possivelmente no GNU Make)?

Suporte de soft link não é necessário.


Esta questão foi fortemente modificada com base na resposta aceita para melhorar a terminologia.

Responder1

Absolutamente não está claro o propósito disso, mas isso fará exatamente o que foi solicitado, usandoCaminho real GNU:

realpath -m --relative-to=release/linux/x86 .
../../..
realpath -m --relative-to=release///./linux/./x86// .
../../..

Responder2

Aqui está uma função shell que retorna um caminho relativo do diretório de origem ao destino usando apenas manipulação de strings - por meio da expansão de parâmetros do shell - sem disco ou acesso à rede. Sem nome de caminho resolução é feito.

Espera dois parâmetros, source-dir e target-dir, ambos nomes de caminho canônicos absolutos e não vazios, ambos podem ter /terminação, nenhum deles precisa existir. Os retornos resultam em uma variável shell $REPLYcomo um caminho relativo de source-dir para target-dir sem trailing /, .se for nulo.

O algoritmo é de uma postagem comp.unix.shell de 2005 que agora ascendeu paraarquivo.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:-.}"
}

Usar como

$ pnrelpath "$HOME" "$PWD"
projects/incubator/nspreon
$ pnrelpath "$PWD" "$gimpkdir"
../../../.config/GIMP
$ pnrelpath "$PWD" "$(cd "$dirnm" && pwd || false)"
# using cd to resolve, canonicalize ${dirnm}

ou comURIestá compartilhando scheme://authority,

$ pnrelpath 'https://example.com/questions/123456/how-to' 'https://example.com/media'
../../../media

Atualizar2022-11-24

Ignorar a whileinstrução na função anterior retornará o que realpath --relative-baseretorna: um caminho relativo do diretório de origem para o diretório de destino se o destino estiver na origem ou abaixo dela, caso contrário, um caminho absoluto. Aplicam-se condições pré e pós semelhantes.

pnrelbase() {
    set -- "${1%/}/" "${2%/}/"      ## '/'-end to avoid mismatch
    REPLY="${2#"$1"}"               ## build result
    # unless root chomp trailing '/', replace '' with '.'
    [ "${REPLY#/}" ] && REPLY="${REPLY%/}" || REPLY="${REPLY:-.}"
}

(finalização da atualização)

informação relacionada