使用简单的 Linux 命令将绝对符号链接转换为相对符号链接

使用简单的 Linux 命令将绝对符号链接转换为相对符号链接

/home/user/system我在包含标准 Linux 结构的路径中有一个完整的子文件系统,其中包含目录/bin, /home, /root, /usr, /var, /etc,...

该子文件系统包含相对或绝对的符号链接。相对符号链接很好,它们保留在/home/user/system.但绝对符号链接是有问题的,因为它们指向子文件系统之外的目标。

作为示例,我们假设绝对符号链接如下(在子文件系统内部可见):

/usr/file1 -> /usr/lib/file1

在整个文件系统中,我们现在有一个链接/home/user/system/usr/file1指向/usr/lib/file1子文件系统外部的文件,而不是文件/home/user/system/usr/lib/file1 里面子文件系统。

我想要一个简单的脚本,最好是一个命令行(rsync,chroot,find,...),将每个绝对符号链接转换为相对符号链接。

在给定的示例中,该相对链接将变为

/usr/file1 -> ../usr/lib/file1

答案1

随着symlinks公用事业由 Mark Lord 提供(许多发行版都提供;如果您的发行版没有,请从来源):

chroot /home/user/system symlinks -cr .

readlink或者,在具有命令和-lname谓词的系统上find(警告:未经测试的代码):

cd /home/user/system &&
find . -lname '/*' -exec ksh -c '
  for link; do
    target=$(readlink "$link")
    link=${link#./}
    root=${link//+([!\/])/..}; root=${root#/}; root=${root%..}
    rm "$link"
    ln -s "$root${target#/}" "$link"
  done
' _ {} +

答案2

纯 bash 和 coreutils,将符号链接更改为相对路径,而../路径中没有不必要的 s:

find . -type l | while read l; do
    target="$(realpath "$l")"
    ln -fs "$(realpath --relative-to="$(dirname "$(realpath -s "$l")")" "$target")" "$l"
done

你可以改变:

  • find .tofind /path/to/directory转换该目录中的符号链接
  • ln -fs进行echo ln -fs空运行

解释:

  • target="$(realpath "$l")"- 找到符号链接目标的绝对路径
  • ln -fs- 创建符号链接 ( -s),强制 ( -f) 重写现有的
  • realpath -s "$l"- 找到符号链接本身的绝对路径
  • dirname "$(realpath -s "$l")"- 查找包含符号链接的目录的绝对路径
  • realpath --relative-to="$(dirname "$(realpath -s "$l")")" "$target"- 查找目标相对于符号链接的路径,换句话说:将绝对路径转换为相对路径

答案3

sshfs 支持在相对链接中转换绝对值,它通过 ssh 挂载远程目录。

命令是:有

sudo sshfs <remote_user>@<remote_ip_address>:/ /home/<host_user>/mntpoint/ -o transform_symlinks -o allow_other

该命令,特别是命令<placeholders>,应适应具体环境。

答案4

find -lname "$PWD/*" | while read link ;do  
   target=$(readlink $link);
   relative_target=$(realpath $target --relative-to=$link/.. --no-symlinks --canonicalize-missing);
   ln --force --symbolic --no-target-directory $relative_target $link
done

"$PWD/*"代表仅转换指向当前工作目录内的绝对链接

相关内容