用原始代码替换所有符号链接

时间:2011-08-23 20:55:09

标签: bash symlink

我有以下目录结构

/symdir
  sym1 -> ../dir1
  sym2 -> ../dir2
  hello.txt

然后

/dir1
  some
  files
  here
/dir2
  more
  files

我想将symdir(sym1,sym2)中的符号链接替换为原始符号。即。

some_awesome_bash_func symdir symdir_output

会创建

/symdir_output
  /dir1
    some
    files
    here
  /dir2
    more
    files
  hello.txt

我将如何做到这一点?

8 个答案:

答案 0 :(得分:64)

我个人的伎俩:

sed -i '' **/*

请注意,我使用的是使用bash globstar选项的**,您可能需要事先启用它:

shopt -s globstar

答案 1 :(得分:21)

您可以使用rsync轻松完成此操作:

rsync symdir/ symdir_output/ -a --copy-links -v

( - 一种方法基本上保留了关于文件的每个细节, - copy-links覆盖-a将符号链接转换为真实文件/目录,-v用于详细)

编辑:

很抱歉,我的解决方案并不能满足您的要求。它将保留符号链接的名称,而不是使用目标名称。 symdir_output将有sym1和sym2而不是dir1和dir2(虽然sym1和sym2将是dir1和dir2的真实副本)。希望它仍然适合你。

答案 2 :(得分:12)

相关答案,此解决方案将文件保留在原始位置并创建副本以代替符号链接

#/bin/bash

for f in $(find . -maxdepth 1 -type l)
do
    cp --remove-destination $(readlink -e $f) $f
done

答案 3 :(得分:10)

可能不是最好的方式,但它有效:

#!/usr/bin/bash

for link in $(find /symdir -type l)
do
  loc="$(dirname "$link")"
  dir="$(readlink "$link")"
  mv "$dir" "$loc"
  rm "$link"
done

答案 4 :(得分:6)

tl; dr:更一般,更可靠的答案:

find -type l -exec sh -c 'PREV=$(realpath -- "$1") && rm -- "$1" && cp -ar -- "$PREV" "$1"' resolver {} \;

“rsync-to-other-destination”方法非常优越,通常可以带来更好的设计。

@PinkFloyd的答案与不寻常的文件名,“埋藏”符号链接或符号链接目录不太一致。我来到这里是因为我想解析目录符号链接,所以我希望其他人也可以出于这个原因找到这个问题。另外,我的cp版本(GNU coreutils 8.25)无法正确处理@ {Pinkis = @FloFloyd使用目录的答案--remove-destination。所以这个答案使用了手册rm

另请注意:

  • 缺少-rf。这是因为符号链接不是目录,不应该需要-r。除非你有限制权限的符号链接(为什么你会想要?),你也不需要-f
  • realpath在这种情况下非常好,因为它允许我们在当前上下文中找出当前系统中的实际位置,而其他任何事情都不重要。此路径不会写入磁盘,因此这不是错误。
  • resolver字符串适用于sh。请参阅man sh
  • 如果某个符号链接被称为--version或类似符号,则必须在任何地方使用双破折号。
  • 由于find的预订保证(“父目录在其内容之前的某处列出”),这将首先替换父目录,然后替换符号链接目录中的任何符号链接。所以它可以与“堆叠”符号链接完美搭配。

答案 5 :(得分:1)

我是这样做的:

ls -la | awk '/-\>/{system("rm "$10); system("cp "$12" .")}'

工作原理:

ls -la输出如下内容:

lrwxr-xr-x  1 username  groupname   44 10 Oct 12:17 Queue.swift -> ../../../Platform/DataStructures/Queue.swift

第10列是Queue.swift,它是本地文件的名称 第12列是../../../Platform/DataStructures/Queue.swift,它是链接目标的名称

awk命令的第一部分是'/-\>/',表示“使用正则表达式匹配包含->的行

awk命令的下一部分是对system

的两次调用

首先system("rm "$10)扩展为system("rm Queue.swift") 这将导致原始文件(符号链接)被删除

第二个是system("cp "$12" ."),它扩展为system("cp ../../../Platform/DataStructures/Queue.swift .")

总而言之,每个文件(这是一个符号链接)会发生什么,首先我们删除符号链接,然后我们将目标文件复制到它的位置。

虽然它不是原始问题的一部分,但我将它与git结合使用。如果您碰巧也是这样做的,那么之后您可以运行git status .,您应该看到一堆类型更改(没有别的),如下所示:

typechange: Queue.swift

答案 6 :(得分:1)

扩展 Julien 的建议。此命令递归地将当前目录中的所有符号链接替换为其目标。

find . -type l -exec sed -i '' {} \;
  • find .:在当前目录中递归搜索
  • -type l:仅查找符号链接
  • -exec sed -i '' {} \;:为每个符号链接运行 sed -i '' PATH。请参阅 Julien 的回答,了解我们为何在此处使用 sed

答案 7 :(得分:0)

这是一个基于@Daniel Haley的更通用的解决方案

它还会保留符号链接以供参考,并要求用户选择要编辑的目录。

ls
read -p 'Which directory do you want to update?: ' linkdir

pushd $linkdir

for linkname in $(find ./ -type l)
do
  orig=$(readlink $linkname)
  mv $linkname ${linkname}.linkbak
  cp $orig $linkname
done

popd