获取两个路径之间的相对链接

获取两个路径之间的相对链接

假设我有两条路径:<source_path><target_path>。我希望我的 shell (zsh) 自动找出是否有办法将<target_path>from表示<source_path>为相对路径。

例如,我们假设

  • <source_path>/foo/bar/something
  • <target_path>/foo/hello/world

结果将是../../hello/world

为什么我需要这个:

我需要创建一个符号链接从<source_path><target_path>使用相对的尽可能使用符号链接,否则当我从 Windows 访问网络上的这些文件时,我们的 samba 服务器无法正确显示该文件(我不是系统管理员,无法控制此设置)

假设<target_path><source_path>是绝对路径,以下创建符号链接指向绝对路径

ln -s <target_path> <source_path>

所以它不能满足我的需要。我需要对数百个文件执行此操作,因此我无法手动修复它。

有任何 shell 内置程序可以处理这个问题吗?

答案1

尝试使用realpath命令(GNU 的一部分coreutils>=8.23),例如:

realpath --relative-to=/foo/bar/something /foo/hello/world

如果您使用的是 macOS,请通过以下方式安装 GNU 版本:brew install coreutils并使用grealpath.

请注意,两个路径都需要存在才能使命令成功。如果您无论如何都需要相对路径,即使其中之一不存在,请添加 -m 开关。

有关更多示例,请参阅将绝对路径转换为给定当前目录的相对路径

答案2

您可以使用以下symlinks命令将绝对路径转换为相对路径:

/tmp$ mkdir -p 1/{a,b,c} 2
/tmp$ cd 2
/tmp/2$ ln -s /tmp/1/* .
/tmp/2$ ls -l
total 0
lrwxrwxrwx 1 stephane stephane 8 Jul 31 16:32 a -> /tmp/1/a/
lrwxrwxrwx 1 stephane stephane 8 Jul 31 16:32 b -> /tmp/1/b/
lrwxrwxrwx 1 stephane stephane 8 Jul 31 16:32 c -> /tmp/1/c/

我们已经有了绝对链接,让我们将它们转换为相对链接:

/tmp/2$ symlinks -cr .
absolute: /tmp/2/a -> /tmp/1/a
changed:  /tmp/2/a -> ../1/a
absolute: /tmp/2/b -> /tmp/1/b
changed:  /tmp/2/b -> ../1/b
absolute: /tmp/2/c -> /tmp/1/c
changed:  /tmp/2/c -> ../1/c
/tmp/2$ ls -l
total 0
lrwxrwxrwx 1 stephane stephane 6 Jul 31 16:32 a -> ../1/a/
lrwxrwxrwx 1 stephane stephane 6 Jul 31 16:32 b -> ../1/b/
lrwxrwxrwx 1 stephane stephane 6 Jul 31 16:32 c -> ../1/c/

参考

答案3

我认为这个 python 解决方案(取自这个答案)也值得一提。将其添加到您的~/.zshrc

relpath() python -c 'import os.path, sys;\
  print os.path.relpath(sys.argv[1],sys.argv[2])' "$1" "${2-$PWD}"

然后你可以这样做,例如:

$ relpath /usr/local/share/doc/emacs /usr/local/share/fonts
../doc/emacs

答案4

# Prints out the relative path between to absolute paths. Trivial.
#
# Parameters:
# $1 = first path
# $2 = second path
#
# Output: the relative path between 1st and 2nd paths
relpath() {
    local pos="${1%%/}" ref="${2%%/}" down=''

    while :; do
        test "$pos" = '/' && break
        case "$ref" in $pos/*) break;; esac
        down="../$down"
        pos=${pos%/*}
    done

    echo "$down${ref##$pos/}"
}

这是解决问题的最简单、最漂亮的方法。

它也应该适用于所有类似 bourne 的 shell。

这里的智慧是:完全不需要外部公用设施,甚至不需要复杂的条件。在类似 bourne 的 shell 上完成任何事情只需要几个前缀/后缀替换和一个 while 循环。

也可通过 PasteBin 获取:http://pastebin.com/CtTfvime

相关内容