Ame*_*ina 31 shell zsh symlink files
假设我有两条路径:<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>
Run Code Online (Sandbox Code Playgroud)
所以它不适合我的需要。我需要为数百个文件执行此操作,因此我无法手动修复它。
任何 shell 内置程序可以解决这个问题?
ken*_*orb 37
尝试使用realpath命令(GNU 的一部分coreutils;>=8.23),例如:
realpath --relative-to=/foo/bar/something /foo/hello/world
Run Code Online (Sandbox Code Playgroud)
如果您使用的是 macOS,请通过以下方式安装 GNU 版本:brew install coreutils并使用grealpath.
请注意,要使命令成功,两条路径都需要存在。如果您仍然需要相对路径,即使其中之一不存在,请添加 -m 开关。
有关更多示例,请参阅将绝对路径转换为给定当前目录的相对路径。
Sté*_*las 11
您可以使用该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/
Run Code Online (Sandbox Code Playgroud)
我们有绝对链接,让我们将它们转换为相对链接:
/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/
Run Code Online (Sandbox Code Playgroud)
我认为这个 python 解决方案(取自这个 SO answer)也值得一提。将此添加到您的~/.zshrc:
relpath() python -c 'import os.path, sys;\
print os.path.relpath(sys.argv[1],sys.argv[2])' "$1" "${2-$PWD}"
Run Code Online (Sandbox Code Playgroud)
然后你可以做,例如:
$ relpath /usr/local/share/doc/emacs /usr/local/share/fonts
../doc/emacs
Run Code Online (Sandbox Code Playgroud)
小智 7
没有任何 shell 内置函数来处理这个问题。不过,我在 Stack Overflow 上找到了解决方案。我已将解决方案复制到此处并稍作修改,并将此答案标记为社区维基。
relpath() {
# both $1 and $2 are absolute paths beginning with /
# $1 must be a canonical path; that is none of its directory
# components may be ".", ".." or a symbolic link
#
# returns relative path to $2/$target from $1/$source
source=$1
target=$2
common_part=$source
result=
while [ "${target#"$common_part"}" = "$target" ]; do
# no match, means that candidate common part is not correct
# go up one level (reduce common part)
common_part=$(dirname "$common_part")
# and record that we went back, with correct / handling
if [ -z "$result" ]; then
result=..
else
result=../$result
fi
done
if [ "$common_part" = / ]; then
# special case for root (no common path)
result=$result/
fi
# since we now have identified the common part,
# compute the non-common part
forward_part=${target#"$common_part"}
# and now stick all parts together
if [ -n "$result" ] && [ -n "$forward_part" ]; then
result=$result$forward_part
elif [ -n "$forward_part" ]; then
# extra slash removal
result=${forward_part#?}
fi
printf '%s\n' "$result"
}
Run Code Online (Sandbox Code Playgroud)
你可以像这样使用这个函数:
source=/foo/bar/something
target=/foo/hello/world
ln -s "$(relpath "$source" "$target")" "$source"
Run Code Online (Sandbox Code Playgroud)