用文件替换符号链接


Answers:


14

对于“简单”的一些定义:

#!/bin/sh
set -e
for link; do
    test -h "$link" || continue

    dir=$(dirname "$link")
    reltarget=$(readlink "$link")
    case $reltarget in
        /*) abstarget=$reltarget;;
        *)  abstarget=$dir/$reltarget;;
    esac

    rm -fv "$link"
    cp -afv "$abstarget" "$link" || {
        # on failure, restore the symlink
        rm -rfv "$link"
        ln -sfv "$reltarget" "$link"
    }
done

以链接名称作为参数运行此脚本,例如通过 find . -type l -exec /path/tos/script {} +


2
谢谢您的编辑,anon,但是该脚本通过在所有必要的位置引用变量来处理文件名,带有空格。更改"$var""${var}"sh / bash中的noop。我删除了一个bashism([[),其余的与POSIX sh兼容。
grawity 2014年

处理符号链接失败的一种更强大的方法是cp,将同一个目录中的一个临时文件保存到同一目录中,然后mv -f将该临时文件保存到原始目录中。这应该防止出现问题,例如人们Ctrl-Crmcp命令之间停滞不前或文件系统被填满(从而甚至阻止了新文件ln的工作)。临时文件名很容易发现,ls -a以后可以根据需要进行清理。
Fooz先生,2015年

顺便提一句,我真的不记得为什么我不只是使用caseabstarget=$(readlink -f "$link")而不是case块了,但这可能是可移植性的原因。
grawity '17

17

仅使用tar将数据复制到新目录可能会更容易。

-H      (c and r mode only) Symbolic links named on the command line will
        be followed; the target of the link will be archived, not the
        link itself.

你可以用这样的东西

tar -hcf - sourcedir | tar -xf - -C newdir

tar --help:
-H, --format=FORMAT        create archive of the given format
-h, --dereference          follow symlinks; archive and dump the files they point to

1
我喜欢您的解决方案,但是我不明白您留言的最后一部分。对我来说,你应该这样做:tar -hcf - sourcedir | tar -xf - -C newdir
Seb DA ROCHA'4

1
同意,此答案将需要根据评论进行更新。
astabada 2014年

1
cp -L是更简单的解决方案
plesiv

@plesiv为true,并且与posix兼容,但并非所有cp实现都将复制目录。
Wyatt8740 '16

15

如果我正确地理解了您的要求-L,则该cp命令的标志应该恰好满足您的要求。

只需复制所有符号链接,它将用它们指向的文件替换它们。


4
谢谢-几乎是我所需要的:我必须做类似的事情:cp -L files tmp/ && rm files && cp tmp/files . 如果您弄清楚,您可能会帮助更多的人……
sage 2013年

5

“轻松”很可能是您的功能。

我可能会编写一个脚本,该脚本使用“ find”命令行实用程序查找符号链接的文件,然后调用rm和cp来删除和替换该文件。您也可能做得很好,也可以通过find检查调用该动作,以确保在移动符号链接之前也有足够的可用空间。

另一个解决方案可能是通过隐藏符号链接的东西(如samba)挂载有问题的文件系统,然后从中复制所有内容。但是在许多情况下,类似的事情会带来其他问题。

您问题的更直接答案可能是“是”。

编辑:根据要求的更具体的信息。根据find手册页,此命令将从/列出所有符号链接文件,深度为2个目录:

find / -maxdepth 2 -type l -print

在这里找到

要找到要执行的操作,请执行以下操作:

find / -maxdepth 2 -type l -exec ./ReplaceSymLink.sh {} \;

我相信它将调用我刚刚编写的一些脚本,并传递您刚刚找到的文件名。或者,您可以将查找输出捕获到文件中(使用“ find [blah]> symlinks.data”等),然后将该文件传递到您编写的脚本中,以优雅地处理原始文件的复制。


?有点通用-您能详细说明吗?
Linker3000 2011年

2
语法为-exec ./ReplaceSymLink.sh {} \;
grawity

这是去查找项目,标记为答案的项目用于替换链接!
Marty Trenouth 2011年

3

这是我使用的oneliner:假定所有本地文件都是“源”中另一个文件的链接。您可以使用模式或“查找”来优化文件选择。请在使用前了解。

对于*中的f; cp --remove-destination source / $ f $ f; 做完了

希望这可以帮助


如何使用readlink:for * in *; do cp ----删除目的地“ $(readlink $ f)”“ $ f”; 完成
迭戈

是的,这是个好主意,但是您对该操作失去了控制。我的解决方案的一个局限性是它不适用于中间有空格或列表很长的文件。可能的最终解决方案是将上面的“ find --exec”与“ remove destination”放在一起。有人要尝试吗?
MastroGeppetto

中间的空格应通过在双引号中放入“ $ f”来缓解。这是我与“ find&xargs”而不是“ for loop”一起使用的方法:查找./ -type l -print0 | xargs -0 -n1 -i sh -c'cp --remove-destination $(readlink“ { }“)” {}“'我已将其发布为可见性的单独答案。superuser.com/a/1329543/499386
迭戈

2
find . -type l -exec cp --dereference --recursive '{}' '{}'.dereferenced \;

将在中创建每个符号链接文件/文件夹的副本<filename>.dereferenced,这比直接替换它们更安全(如果不太方便)。留给读者练习是将复制的数据移至符号链接的文件名。


2

使用一些先前的想法,以下命令将以原始副本的形式递归替换每个符号链接:

find . -type l -exec bash -c "echo 'Replacing {} ...';  cp -LR '{}' '{}'.dereferenced;  rm '{}';  mv '{}'.dereferenced '{}'" \;

1

那里有很多好的答案,但是我,因为您在寻找简单的东西

for i in *; do link=$(readlink $i) && rm $i && mv $link $i; done

进行一些增强将有助于查找符号链接:对于`find中的lnk。型l`; 做src = $(readlink $ lnk)&& rm $ lnk && mv $ src $ lnk; 完成(虽然未进行等级测试,但请小心反引号)
Roman Susi

1

当您通常希望gwenview跟随链接并复制文件时,我在gwenview复制链接时遇到了相同的问题。

我通过跟踪所有链接并将所有指向的文件复制到该目录来“清理”目录的操作是创建一个临时目录,运行例如

"for file in `ls`; do cp -L $file scratchdir/$file; done; mv scratchdir/* ./" 

这太危险了,不能放入脚本,因为没有检查,但是它解决了我的问题。




0

我做了一个单行版本,因为我的网络酒店不允许使用bash脚本,因此对我来说效果很好:

before:
> find . -type l | wc -l
358

> for link in `find . -type l` ; do echo "$link : "; ls -al $link ; cp $link notalink; unlink $link; mv notalink $link ; ls -al $link; done
...

after:
> find . -type l | wc -l
0
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.