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


29

我有一个路径中一个完整的子文件系统/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

4
对于那些有兴趣尝试解决此问题的人,以下是SO尝试的250k rep用户:stackoverflow.com/questions/2564634/…。该线程中有几种潜在的解决方案,但每种解决方案都有其处理的特定情况,而其他情况则没有。
slm

Answers:


20

使用Mark Lord提供的symlinks实用程序(提供许多发行版本;如果您没有,请从源代码构建它):

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
' _ {} +

这将是一个不错的解决方案!但是,表达式_ {} +在查找结束时意味着什么?另外,我得到一个错误,find: paths must precede expression: ksh这似乎没有什么意义(如路径preceeds的KSH表达)。
亚历克斯

@Alex _$0为外壳片断,并{} +通过参数列表它成为取代$1$2等它for link; do …会遍历(它的代名词for link in "$@"; do …)。来自的错误find是由于输入错误造成的(我以某种方式设法在输入的引号周围键入反引号而不是单引号-lname)。
吉尔(Gilles)“所以,别再邪恶了”

现在该脚本运行,但是没有按预期运行。也许我不够精确,所以我已经更新了问题。
亚历克斯

@Alex有什么问题?我认为原理是合理的,但是我可能在编码方面犯了一些错误。你尝试了symlinks吗?它将解决您的问题-基本上就是它的设计目标(烦人的是您必须将其chroot地运行(fakechroot应该可以解决问题))。
吉尔斯(Gilles)'所以

1
我强烈建议您立即使用一种解决方案,而无需安装其他组件。
亚历克斯

4

纯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 .find /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" -查找相对于符号链接的目标路径,换句话说:将绝对路径转换为相对路径

1
我建议添加一个if子句以跳过断开的链接。
fuenfundachtzig

0

这个bash片段应该做到这一点。第一个表格将打印其内容;第二个会做。我会仔细检查输出,因为它具有破坏性- ln -f覆盖现有链接。

TOP=/home/user/system
cd $TOP
find * -type l -print | while read l; do echo ln -sf $TOP$(readlink $l) $l; done
find * -type l -print | while read l; do      ln -sf $TOP$(readlink $l) $l; done

除了使用空格的名称会失败之外,这不是错误的方法吗?它以绝对路径为前缀吗?
fuenfundachtzig


0

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

命令是:

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

该命令,尤其是<placeholders>,应适应特定的环境。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.