使用 cp 将软链接转换为硬链接

使用 cp 将软链接转换为硬链接

cp命令的页面提供以下info选项:--preserve=

links
在目标文件中保留相应源文件之间的任何链接。注意-L' or-H',这个选项将符号链接转换为硬链接

接下来是一个我现在不明白的例子;无论如何:

问题: 如何将软链接变成硬链接cp?还有回来的方法吗[将硬链接转换为软链接]?


次要问题: 哪里有在上面的引用中发挥作用吗?我理解-L和的目的-H,我能够复制功能齐全的软链接等,但到目前为止我还没有设法将软链接变成硬链接。

答案1

信息页面中的示例向您展示了该示例有点难以理解:

$ mkdir c; : > a; ln -s a b; cp -aH a b c; ls -i1 c
74161745 a
74161745 b

让我们将其分解为其组件命令:

  • mkdir c;: 创建目录c/
  • : > a;:只是创建空文件的快速方法。它相当于echo "" > a.:是一个内置的 bash,它不执行任何操作,请参阅help :
  • ln -s a b:创建一个软链接来a调用b。此时,当前目录的内容如下:

    $ ls -l | cc2ter 
    total 4
    -rw-r--r-- 1 terdon terdon    0 Oct  9 02:50 a
    lrwxrwxrwx 1 terdon terdon    1 Oct  9 02:50 b -> a
    drwxr-xr-x 2 terdon terdon 4096 Oct  9 02:50 c
    

    请注意,这b是一个符号链接(软链接),它并不指向与以下相同的 inode a

    $ ls -i1c a b
    16647344 a
    16647362 b
    
  • cp -aH a b c;:将文件复制ab目录中c。这是转换发生的地方,传递给的选项cp是:

    -a, --archive
          same as -dR --preserve=all
    -d    same as --no-dereference --preserve=links
    -H    follow command-line symbolic links in SOURCE
    

    -H是必要的,因为(来自info cp):

    当从符号链接复制时,“cp”通常仅在不递归复制时才遵循该链接。

    由于-a激活递归复制 ( -R),-H因此需要遵循符号链接。-H意味着尽管递归,链接仍被跟踪,并将导致在目标目录中建立硬链接。这些是c/最后一步之后的内容(第一列是索引节点号):

    $ ls -li c 
    total 0
    17044704 -rw-r--r-- 2 terdon terdon 0 Oct  9 02:50 a
    17044704 -rw-r--r-- 2 terdon terdon 0 Oct  9 02:50 b
    

现在关于它到底是如何工作的,据我通过使用它可以弄清楚,cp --preserve=links结合-L-H将符号链接转换为硬链接,如果链接和目标都被复制到相同的目录


事实上,作为OP发现至少在 Debian 系统上,cp --preserve=links如果目标目录相同,就足以将符号链接转换为硬链接。

答案2

我已在文档中向 coreutils 团队 @gnu.org 发送了有关可能错误的报告,info cp并得到了回复:

这里的文档有点简洁。主要问题是 -a 暗示 -d 并暗示 --no-dereference ,这是让命令按预期工作所必需的。需要 IE --no-dereference 来隐式停止 cp 遵循源中的符号链接。

要验证并拆分此处演示的详细信息:

$ mkdir links; : > a; ln -s a b;

在这里我们看到 -d 覆盖了后面的 -H。因此,我们首先不会取消引用符号链接。

$ rm links/*; cp -H -d a b links
$ l links/
lrwxrwxrwx. 1 padraig 1 Oct 10 09:37 b ▪▶ a
-rw-rw-r--. 1 padraig 0 Oct 10 09:37 a

在这里我们看到 -H 现在被尊重,因为它排在最后,因此在源中遵循符号链接,从而在目标中产生硬链接。

$ rm links/*
$ rm links/*; cp -d -H a b links
$ l links
-rw-rw-r--. 2 padraig 0 Oct 10 09:37 b
-rw-rw-r--. 2 padraig 0 Oct 10 09:37 a

我将通过以下内容使文档更加明确:

diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index b273627..aeed4ca 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -8257,9 +8257,11 @@ $ mkdir c; : > a; ln -s a b; cp -aH a b c; ls -i1 c
 @noindent

请注意输入:@file{b}是常规文件 的符号链接@file{a},但目标目录 中的文件@file{c/}是硬链接的。

  • 由于@option{-a}暗示@option{--preserve=links},并且由于@option{-H}告诉@command{cp}取消引用命令行参数,因此它会看到两个具有相同索引节点号的文件,并保留感知的硬链接。
  • 因为@option{-a}意味着@option{--no-dereference}它将复制符号链接,但后者@option{-H}告诉@command{cp}取消引用命令行参数,然后它会看到两个具有相同索引节点号的文件。然后,该@option{--preserve=links} 选项也暗示@option{-a}将保留感知的硬链接。

答案3

将硬链接转换为符号链接是很困难的。在硬链接的情况下,文件系统上有一个数据块,有两个或多个文件条目指向它。没有“来源”和“目的地”;它实际上是一个具有多个等效名称的文件。您可以使用 GNU find 来识别这些:

sauer@zipper:~$ find . -type f -links +1 -printf "%i: %p (%n)\n"
609: ./link1 (2)
609: ./link2 (2)

一旦你获得了具有相同 inode 的所有文件,你就必须选择一个作为“真实”文件,然后用主文件的符号链接替换所有其他文件。可能的方法是使用这个:

sauer@zipper:~$ find . -type f -links +1 -printf "%i %p\n" | sort -nk1
609 ./link1
609 ./link2

然后让一个脚本弄清楚如何选择具有相同数字的值之一以使所有其他值链接到它。也许第一个成为目标,并且具有相同 inode 的任何其他节点都会符号链接到它。这是一个非常简单、未经测试的 shell 脚本示例

#!/bin/sh
prev=""
target=""
find /tmp -type f -links +1 -printf "%i %p\n" | sort -nk1 \
| while read inode file
do
  if [[ $inode != $prev ]]
  then
     target="$file"
     prev=$inode
  else
    ln -sf "$target" "$file"
  fi
done

存在潜在的问题,因为如果 find 中的路径(本例中为 /tmp)不是绝对路径,则可能会使用无效目标创建来自不同目录的链接。但总体思路应该没问题。

相关内容