如何将符号链接转换为常规文件?

时间:2011-12-04 17:52:00

标签: linux symlink

将符号链接转换为常规文件(即符号链接目标的副本)的最直接方法是什么?

假设filenametarget的符号链接。将其变成副本的明显程序是:

cp filename filename-backup
rm filename
mv filename-backup filename

是否有更直接的方式(即单个命令)?

15 个答案:

答案 0 :(得分:49)

没有单个命令可以将符号链接转换为常规文件。最直接的方法是使用readlink查找符号链接指向的文件,然后通过符号链接复制该文件:

cp --remove-destination `readlink bar.pdf` bar.pdf

当然,如果bar.pdf实际上是一个常规文件,那么这将破坏文件。因此,建议进行一些健全检查。

答案 1 :(得分:21)

只是重复其他人的答案,但添加“健全性检查”以确保传入的链接实际上是一个符号链接:

removelink() {
  [ -L "$1" ] && cp --remove-destination "$(readlink "$1")" "$1"
}

这就是说如果文件是符号链接,则运行复制命令。

答案 2 :(得分:17)

for f in $(find -type l);do cp --remove-destination $(readlink $f) $f;done;
  • 检查当前目录和子目录find -type l
  • 中的符号链接
  • 获取链接文件路径readlink $f
  • 删除符号链接并复制文件cp --remove-destination $(readlink $f) $f

答案 3 :(得分:9)

对于文本文件,sed命令可以在一行中执行此操作,如果您将就地开关(-i)传递给它。这是因为sed对文件进行了一次传递,将输出捕获到一个临时文件中,随后将其重命名为与原始文件匹配。

只需执行不带变换的内联sed

sed -i ';' /path/to/symbolic/link

答案 4 :(得分:7)

在OSX上

  

rsync`readlink bar.pdf`bar.pdf

答案 5 :(得分:7)

rsync上不需要任何有趣的shell脚本cp或特殊的GNU选项。很简单:

$ mv target link

如果我们不了解目标,我们会将$(readlink link)替换为上面的target

$ mv $(readlink link) link

mv实用程序对应于POSIX类系统上的rename系统调用(至少在不跨不同文件系统卷操作时)。 rename系统调用会在单个操作中删除目标对象(如果存在)。

我们可以简单地mv目标文件到符号链接:

$ touch target
$ ln -sf target link
$ ls -l target link
lrwxrwxrwx 1 kaz kaz 6 Sep  7  2016 link -> target
-rw-rw-r-- 1 kaz kaz 0 Sep  7  2016 target
$ mv target link
$ ls -l target link
ls: cannot access target: No such file or directory
-rw-rw-r-- 1 kaz kaz 0 Sep  7  2016 link

如果我们跨卷进行此操作,则会进行模拟。 GNU Coreutils mv首先尝试rename系统调用。当失败时,它使用unlink删除目标符号链接,并执行副本:

$ touch /tmp/target
$ ln -sf /tmp/target link
$ ls -l /tmp/target link
lrwxrwxrwx 1 kaz kaz 11 Sep  7  2016 link -> /tmp/target
-rw-rw-r-- 1 kaz kaz  0 Sep  7 16:20 /tmp/target
$ strace mv /tmp/target link
[ ... snip ... ]
stat("link", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
lstat("/tmp/target", {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
lstat("link", {st_mode=S_IFLNK|0777, st_size=11, ...}) = 0
rename("/tmp/target", "link")           = -1 EXDEV (Invalid cross-device link)
unlink("link")                          = 0
open("/tmp/target", O_RDONLY|O_NOFOLLOW) = 3
fstat(3, {st_mode=S_IFREG|0664, st_size=0, ...}) = 0
open("link", O_WRONLY|O_CREAT|O_EXCL, 0600) = 4
fstat(4, {st_mode=S_IFREG|0600, st_size=0, ...}) = 0
fadvise64(3, 0, 0, POSIX_FADV_SEQUENTIAL) = 0
read(3, "", 65536)                      = 0
[ ... ]
close(0)                                = 0
close(1)                                = 0
exit_group(0)                           = ?
+++ exited with 0 +++
$ ls -l /tmp/target link
ls: cannot access /tmp/target: No such file or directory
-rw-rw-r-- 1 kaz kaz 0 Sep  7 16:20 link

答案 6 :(得分:4)

cp 可以删除目标文件:

cp --remove-destination target filename

答案 7 :(得分:2)

许多人已经说过以下解决方案:

cp --remove-destination `readlink file` file

但是,这不适用于符号链接的目录。

添加递归强制也不会有效:

cp -rf --remove-destination `readlink file` file

cp:无法复制目录,'路径/文件,自身','文件'

因此,首先完全删除符号链接可能更安全:

resolve-symbolic-link() {
  if [ -L $1 ]; then
      temp="$(readlink "$1")";
      rm -rf "$1";
      cp -rf "$temp" "$1";
  fi
}

不完全是你所希望的单行,但把它放到你的shell环境中,它可以。

答案 8 :(得分:1)

这对我来说很有效(编辑以使用空格):

find . -type l | while read f; do /bin/cp -rf --remove-destination -f $(find . -name $(readlink "${f}")) "${f}";done;

允许您递归地将当前工作文件夹下的所有符号链接转换为其常规文件。也不要求你覆盖。存在“/ bin / cp”,以便您可以绕过操作系统上可能的cp -i别名,从而阻止“-rf”工作。

答案 9 :(得分:1)

此解决方案适用于符号链接文件和符号链接文件夹/子文件夹。

一行,不需要脚本。 这对于在别处输出或转移符号链接非常理想。

将所有内容放在文件夹中。

rsync --archive --copy-links --recursive folderContainingSymlinkFilesAndSymlinkFoldersAndSubfolders myNewFolder

答案 10 :(得分:0)

没有单一命令。但是,如果您不想要副本并且您想要的是另一个引用,则可以使用链接(也称为“硬链接”)替换符号链接。这只适用于它们位于同一分区BTW。

rm filename
ln target filename

答案 11 :(得分:0)

使用-L标志,Rsync可以为你使用符号链接。

[user@workstation ~]$ rsync -h | grep -- -L
 -L, --copy-links            transform symlink into referent file/dir

这很简单:rsync -L <symlink> <destination>

答案 12 :(得分:0)

如果是“相对”符号链接,你可以在@jared回答中添加一个awk语句:

for f in $(find . -type l); do /bin/cp -rf --remove-destination -f $(find . \! -type l -name $(readlink $f | awk -F"../" '{print $NF}')) $f;done;

如果您有指向目录的符号链接,则需要使用更激进的方法,因为cp --remove-destination与symlinks目录无法正常工作

for f in `find . -type l`; do (cd `dirname $f`; target=`basename $f`; source=`readlink $target` ; rm -rf $target && cp -r $source $target); done

可以肯定,这可以用更少的开销来编写。但在我看来这是非常好的。

答案 13 :(得分:0)

如果您发现自己经常这样做,另一种方法是将kbrock的答案调整为shell脚本并将其放入/ usr / bin /。有点像:

if [ $# -ne 1 ] 
then
  echo "Usage: $0 filename"
  exit 1
fi
[ -L "$1" ] && cp --remove-destination "$(readlink "$1")" "$1"

chmod + x it,然后将其作为普通命令运行。

答案 14 :(得分:0)

将所有file.txt从链接更改为文件。

<div class="sourcesContainer">
  <ul>
    <li class="slidecontainer">
      <input type="range" min="0" max="100" value="0" class="slider">
    </li>
    <li class="slidecontainer">
      <input type="range" min="0" max="100" value="0" class="slider">
    </li>
    <li class="slidecontainer">
      <input type="range" min="0" max="100" value="0" class="slider">
    </li>
    <li class="slidecontainer">
      <input type="range" min="0" max="100" value="0" class="slider">
    </li>
  </ul>
</div>
相关问题