将符号链接转换为常规文件(即符号链接目标的副本)的最直接方法是什么?
假设
filename
是 target
的符号链接。 将其转换为副本的明显步骤是:
cp filename filename-backup
rm filename
mv filename-backup filename
有没有更直接的方法(即单个命令)?
没有单个命令可以将符号链接转换为常规文件。 最直接的方法是使用
readlink
查找符号链接指向的文件,然后通过符号链接复制该文件:
cp --remove-destination `readlink bar.pdf` bar.pdf
当然,如果
bar.pdf
实际上是一个常规文件,那么这将破坏该文件。 因此,建议进行一些健全性检查。
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
只是对其他答案的重新整理,但添加了“健全性检查”以确保传入的链接实际上是符号链接:
removelink() {
[ -L "$1" ] && cp --remove-destination "$(readlink "$1")" "$1"
}
这就是说,如果文件是符号链接,则运行复制命令。
对于文本文件,如果您将
in-place开关 (
sed
) 传递给 -i
命令,则可以在一行中执行此操作。这是因为 sed
对文件进行了一次传递,将输出放入临时文件中,随后将其重命名以匹配原始文件。
只需执行内联
sed
,无需转换:
sed -i ';' /path/to/symbolic/link
在 OSX 上
rsync `readlink bar.pdf` bar.pdf
cp可以删除目标文件:
cp --remove-destination target filename
许多人已经提出了以下解决方案:
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 环境中,就可以了。
此解决方案适用于符号链接文件和符号链接文件夹/子文件夹。
一行,无需脚本。 这对于导出或转移符号链接到其他地方来说是理想的选择。
将所有内容放入文件夹中。
rsync --archive --copy-links --recursivefolderContainingSymlinkFilesAndSymlinkFoldersAndSubfolders myNewFolder
如果链接的源和目标都在同一分区上,最直接的方法是将软链接转换为硬链接(我假设当前链接是软链接)。就这样完成了。
这样就有效地完成了‘复制’。如果您检查所有软符号链接的目录的磁盘使用大小(du),然后执行硬链接转换(如下),并再次检查,“之后”du 大小反映了实际的原始文件大小。然后您可以随时查看链接的来源,而不会影响硬链接的目标。
find . -type l -exec bash -c 'ln -f "$(readlink -m "$0")" "$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 它,然后像普通命令一样运行它。
将所有 file.txt 从链接更改为文件。
for f in *.txt; do echo $(readlink $f) $f | awk '{print "rsync -L "$1" "$2}'; done | bash
我尝试将以上所有内容综合成一个完整的解决方案。我做了一个“深度去链接”,所以即使不需要,也会有一个额外的调用来查找。有人可能想添加一个 --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
没有单一的命令。 但是,如果您不需要副本并且您想要的只是另一个引用,则可以将符号链接替换为链接(也称为“硬链接”)。 顺便说一句,这仅在它们位于同一分区时才有效。
rm filename
ln target filename
Rsync 可以使用 -L 标志自然地为您引用符号链接。
[user@workstation ~]$ rsync -h | grep -- -L
-L, --copy-links transform symlink into referent file/dir
就这么简单:
rsync -L <symlink> <destination>
如果是“相对”符号链接,您可以向 @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
可以肯定的是,这可以用更少的开销来编写。但我认为读起来相当不错。
这对我来说非常有效(编辑以使用空格):
find . -type l | while read f; do /bin/cp -rf --remove-destination -f $(find . -name $(readlink "${f}")) "${f}";done;
允许您递归地将当前工作文件夹下的所有符号链接转换为其常规文件。也不要求您覆盖。 “/bin/cp”的存在使您可以绕过操作系统上可能阻止“-rf”工作的 cp -i 别名。
find . -type l -exec bash -c 'realpath=$(readlink -f "{}"); cp -r --remove-destination "$realpath" "{}"' \;
为我工作