如何“重新链接”很多断开的符号链接?


54

我有一个目录树,该目录树有一堆符号链接到/home... 下的文件,但是,我已经移动/home/mnt/home并且需要一种“重新链接”所有符号链接的方法。是否存在这样的功能,或者我需要编写脚本来做到这一点?

例如,我有如下内容:

[root@trees ~]# ls -l /mnt/home/someone/something
total 4264
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 a -> /home/someone/someotherthing/a
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 b -> /home/someone/someotherthing/b
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 c -> /home/someone/someotherthing/c
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 d -> /home/someone/someotherthing/d
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 e -> /home/someone/someotherthing/e

/mnt/home/someone/something/subdir:
total 4264
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 a -> /home/someone/someotherthing/subdir/a
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 b -> /home/someone/someotherthing/subdir/b
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 c -> /home/someone/someotherthing/subdir/c
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 d -> /home/someone/someotherthing/subdir/d
lrwxrwxrwx 1 jnet www-data      55 2011-08-07 13:50 e -> /home/someone/someotherthing/subdir/e

我想要一个将找到所有符号链接并重新链接到相同位置但在下面/mnt/home而不是下面的命令/home

是否存在这样的命令?

Answers:


55

没有命令可以重新定向符号链接,您所能做的就是删除它并创建另一个。假设您具有GNU实用程序(例如在非嵌入式Linux或Cygwin下),则可以使用-lnameprimary find来按其目标匹配符号链接,并readlink读取链接的内容。未经测试:

find /mnt/home/someone/something -lname '/home/someone/*' \
     -exec sh -c 'ln -snf "/mnt$(readlink "$0")" "$0"' {} \;

使这些符号链接相对更好。symlinks在许多Linux发行版中都有一个便捷的小工具(最初由Mark Lords负责,现在由J. Brandt Buckley维护)。在移动之前,或在如上所述还原有效链接之后,请运行symlinks -c /mnt/home/someone/something将指定目录下的所有绝对符号链接转换为相对符号链接,除非它们跨越文件系统边界。


没冒犯,这是一个很好的单线方式,但是Bash的字符串替换可能会在路径更改时产生一些魔术效果,并且会更容易。
0xC0000022L 2012年

@STATUS_ACCESS_DENIED如何?唯一的字符串操作是在/mnt路径之前添加;除了串联之外,您不需要进行任何更复杂的字符串操作。
吉尔斯(Gilles)'所以

@吉尔斯:对不起,我想更多地考虑你对相对路径的看法。对于示例的确切“翻译”,您当然是正确的。
0xC0000022L 2012年

13

我知道这并不是作者所要求的,但是似乎他们已经有了答案,所以我为喜欢这个问题的其他人添加了这个答案。

如果需要更灵活的解决方案,例如具有一堆损坏的符号链接,可以通过替换部分符号链接的目标进行修复,则以下内容将有所帮助。

例如。更改用户名后,在完成移动之后,在许多链接的目标中将旧用户名替换为新用户名。创建一个名为replace-simlinks的脚本,如下所示:

#!/bin/bash
link=$1
# grab the target of the old link
target=$(readlink -- "$1")

# replace the first occurrence of oldusername with newusername in the target string
target=${target/oldusername/newusername}

# Test the link creation
echo ln -s -- "$target" "$link"

# If the above echo shows the correct commands are being issued, then uncomment the following lines and run the command again
#rm $link
#ln -s "$target" "$link"

并使用以下命令调用它:

find /home/newusername/ -lname '/home/oldusername/*' -exec ~/bin/replace-simlinks {} \;

希望这对某人有帮助

编辑:感谢Gilles在此脚本上的启动以及有关使用symlinks脚本使链接相对的提示。


1
我发现此解决方案更好,因为它使用字符串替换,这在必须更改路径中间的文件夹名称的情况下很有用。如果需要,该解决方案也很容易修改以执行更复杂的转换。
Gallaecio

我建议引用字符串替换的参数,因为使用斜杠必须这样做,例如在OP问题中的路径。target=${target/"/home"/"/mnt/home"}很有帮助。谢谢。
沃尔特·尼森

3

创建/home到的符号链接/mnt/home,所有现有的符号链接将再次有效。


2
在程序意识到符号链接并根据事实而有所不同的情况下,绑定安装通常不如符号链接易碎...
0xC0000022L
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.