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

问题描述 投票:0回答:17

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

假设

filename
target
的符号链接。 将其转换为副本的明显步骤是:

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

有没有更直接的方法(即单个命令)?

linux symlink
17个回答
70
投票

没有单个命令可以将符号链接转换为常规文件。 最直接的方法是使用

readlink
查找符号链接指向的文件,然后通过符号链接复制该文件:

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

当然,如果

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


39
投票
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

22
投票

只是对其他答案的重新整理,但添加了“健全性检查”以确保传入的链接实际上是符号链接:

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

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


19
投票

对于文本文件,如果您将

in-place
开关 (sed) 传递给
-i
命令,则可以在一行中执行此操作。这是因为
sed
对文件进行了一次传递,将输出放入临时文件中,随后将其重命名以匹配原始文件。

只需执行内联

sed
,无需转换:

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

7
投票

在 OSX 上

rsync `readlink bar.pdf` bar.pdf


3
投票

cp可以删除目标文件:

cp --remove-destination target filename

3
投票

许多人已经提出了以下解决方案:

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 环境中,就可以了。


3
投票

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

一行,无需脚本。 这对于导出或转移符号链接到其他地方来说是理想的选择。

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

rsync --archive --copy-links --recursivefolderContainingSymlinkFilesAndSymlinkFoldersAndSubfolders myNewFolder


2
投票

如果链接的源和目标都在同一分区上,最直接的方法是将软链接转换为硬链接(我假设当前链接是软链接)。就这样完成了。

这样就有效地完成了‘复制’。如果您检查所有软符号链接的目录的磁盘使用大小(du),然后执行硬链接转换(如下),并再次检查,“之后”du 大小反映了实际的原始文件大小。然后您可以随时查看链接的来源,而不会影响硬链接的目标。

find . -type l -exec bash -c 'ln -f "$(readlink -m "$0")" "$0"' {} \;

1
投票

如果您发现自己经常这样做,另一种方法是将 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 它,然后像普通命令一样运行它。


1
投票

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

for f in *.txt; do echo $(readlink $f) $f | awk '{print "rsync -L "$1" "$2}'; done | bash

1
投票

我尝试将以上所有内容综合成一个完整的解决方案。我做了一个“深度去链接”,所以即使不需要,也会有一个额外的调用来查找。有人可能想添加一个 --deep 选项来防止重复查找,在大型目录树的情况下,这可能会非常昂贵。 (抱歉所有的 1 行)

#!/bin/bash
[[ -z $1 ]] && target="." || target=$1

last_wc=0
links=$(/bin/find $target -type l)
rc=$? && [[ $rc -ne 0 ]] && exit $rc

while true; do
    wc=$(echo $links | /bin/wc -w)
    [[ $wc -eq $last_wc ]] && break
    for f in $links; do
        link_target=$(/bin/readlink --canonicalize-existing --no-newline --verbose "$f")
        [[ $? -ne 0 ]] && continue

        if [[ -d "$link_target" ]]; then
            cmd="/bin/rm -f '$f' && /bin/cp -r '$link_target' '$f'"
        else
            cmd="/bin/rm -f '$f' && /bin/cp '$link_target' '$f'"
        fi
        eval $cmd
        [[ $? -ne 0 ]] && echo "WARNING: Problem running '$cmd'" >&2
    done
    last_wc=$wc
    links=$(/bin/find $target -type l)
done

0
投票

没有单一的命令。 但是,如果您不需要副本并且您想要的只是另一个引用,则可以将符号链接替换为链接(也称为“硬链接”)。 顺便说一句,这仅在它们位于同一分区时才有效。

rm filename
ln target filename

0
投票

Rsync 可以使用 -L 标志自然地为您引用符号链接。

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

就这么简单:

rsync -L <symlink> <destination>


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 无法与符号链接目录正确配合使用

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

可以肯定的是,这可以用更少的开销来编写。但我认为读起来相当不错。


0
投票

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

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

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


0
投票
find . -type l -exec bash -c 'realpath=$(readlink -f "{}"); cp -r --remove-destination "$realpath" "{}"' \;

为我工作

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.