查找某个目录的所有符号链接并将目标更改为另一个目录

查找某个目录的所有符号链接并将目标更改为另一个目录

我有一堆/home指向文件和子目录的符号链接/foo。我想定位新目录/bar.

我的方法是查看所有无效的符号链接并验证它们是否指向/foo.然后我做了以下事情:

sudo find . -type l -! -exec test -e {} \; -exec sh -c '\
   old_link_target=$(readlink "$0"); \
   new_link_target=${old_link_target//foo/bar}; \
   ln -snf $new_link_target $0' {} \;

但是,我想要一种更精确的方法,该方法不包括关注无效符号链接的初始步骤。因此,对于这个问题,假设/foo仍然存在,因此需要另一种方法。

答案1

GNUly:

find . -lname '/foo*' -printf '%p\0%l\0' |
  awk -vRS='\0' '
    {
      getline target
      sub("^/foo", "/bar", target)
      printf("%s\0%s\0", target, $0)
    }' |
  xargs -r0n2 ln -sfT

或者使用最近的 GNU sed

find . -lname '/foo*' -printf '%l\0%p\0' |
  sed -z 's|^/foo|/bar|;n' |
  xargs -r0n2 ln -sfT

请注意,您可能会影响符号链接的所有权(例如,如果它们位于不属于他们的目录中,但具有写入权限并具有t位设置(如/tmp))。

为了防止这种情况,你可以使用 GNUtar来代替:

find . -lname '/foo*' -print0 |
  tar --null -T - -cf - --transform='s@^/foo@/bar@' |
  tar xpf -

答案2

这是一个很小的测试集:

mkdir ./tmp1 ./tmp2    
touch ./tmp1/file1 ./tmp2/file2
ln -s ./tmp1 ./tmp3
ls -H ./tmp3

输出

file1

所以现在我要...

mount --bind ./tmp2 ./tmp1
ls -H ./tmp3

输出

file2

多达!现在,所有曾经指向的链接都./tmp1将自动指向./tmp2- 事实上,也是如此,./tmp1因为它们是相同的安装点。如果./tmp2包含了我可能会做的儿童安装:

mount --rbind ./tmp2 ./tmp1

并递归地--bind mount编辑树。这甚至还不是 Linux 内核 vfs 的皮毛共享子树 mount选项。

在 Linux 系统上,您不必过多关心文件指向哪个目录,因为您可以使用内核的虚拟文件系统挂载树以原子方式影响该文件的位置 - 它由您使用。您可以在 中管理整个事情/etc/fstab

>>/etc/fstab \
printf '%s %s none bind,defaults 0 0\n' \
    "/bar" "/foo"

你的问题就解决了。

相关内容