如何使用每个文件的硬链接递归复制目录

Gud*_*Orn 77 hard-link cp recursive files

我想创建一个目录树的“副本”,其中每个文件都是原始文件的硬链接

示例:我有一个目录结构:

dirA/
dirA/file1
dirA/x/
dirA/x/file2
dirA/y/
dirA/y/file3
Run Code Online (Sandbox Code Playgroud)

这是预期的结果,目录树的“副本”,其中每个文件都是原始文件的硬链接:

dirB/            #  normal directory
dirB/file1       #  hardlink to dirA/file1
dirB/x/          #  normal directory
dirB/x/file2     #  hardlink to dirA/x/file2
dirB/y/          #  normal directory
dirB/y/file3     #  hardlink to dirA/y/file3
Run Code Online (Sandbox Code Playgroud)

Gud*_*Orn 76

在 Linux(更准确地说是 GNU 和busyboxcp以 Linux 作为内核的系统上常见的实现)和最近的 FreeBSD 上,这是如何:

cp -al dirA dirB
Run Code Online (Sandbox Code Playgroud)

有关更便携的解决方案,请参阅 Stéphane Chazelas 使用 pax 和 cpio 的答案


Sté*_*las 29

POSIXly,您可以pax在读+写模式下使用以下-l选项:

pax -rwlpe -s /A/B/ dirA .
Run Code Online (Sandbox Code Playgroud)

-pe保留被复制文件的所有可能的属性(在这种情况下,只有目录),如GNUcp-a一样)。

现在,虽然是标准的,但该命令不一定非常便携

首先,许多基于 GNU/Linux 的系统pax默认不包含(即使这是一个非可选的 POSIX 实用程序)。

然后,一些实现的许多错误和不一致性导致该代码出现许多问题。

  • 由于一个错误,Solaris 10 pax(至少)-rwl在与-s. 出于某种原因,它似乎将替换应用于原始路径和复制路径。所以在上面,它会尝试做一些link("dirB/file", "dirB/file")而不是link("dirA/file", "dirB/file").
  • 在 FreeBSD 上,pax不会为符号链接类型的文件创建硬链接(POSIX 允许的行为)。不仅如此,但它也适用于替代的符号链接的目标(行为通过POSIX允许的)。因此,举例来说,如果有一个foo -> AA符号链接dirA,它将成为foo -> BAdirB

此外,如果您想使用其内容存储在$srcand 中的任意文件路径执行相同操作$dst,那么重要的是要意识到pax -rwl -- "$src" "$dst"创建$srcinside的完整目录结构$dst(必须存在并且是一个目录)。例如,如果$srcfoo/bar,则$dst/foo/bar创建。

相反,如果您想$dst成为 的副本$src,最简单的方法可能是:

absolute_dst=$(umask 077 && mkdir -p -- "$dst" && cd -P -- "$dst" && pwd -P) &&
(cd -P -- "$src" && pax -rwlpe . "$absolute_dst")
Run Code Online (Sandbox Code Playgroud)

(这也可以解决上面提到的大多数问题,但如果$dst以换行符结尾的绝对路径会失败)。

现在这对没有pax.

有趣的是,它pax是由 POSIX 创建的,用于合并tarcpio命令的功能。

cpio是一个历史悠久的Unix 命令(从 1977 年开始),而不是 POSIX 发明,并且还有一个 GNU 实现(不是pax一个)。因此,即使它不再是标准命令(尽管它在 SUSv2 中),但它仍然很常见,并且有一组您通常可以依赖的核心功能。

相当于pax -rwl将是cpio -pl。然而:

  1. cpio 使用 stdin 上的输入文件列表而不是参数(换行符分隔,这意味着不支持带有换行符的文件名)
  2. 必须指定所有文件(通常您将find(find并且cpio由同一个人共同开发)的输出提供给它)。
  3. 元数据不被保留(某些cpio实现可以选择保留一些,但没有可移植性)。

所以用cpio

absolute_dst=$(umask 077 && mkdir -p -- "$dst" && cd -P -- "$dst" && pwd -P) &&
(cd -P -- "$src" && find . | cpio -pl "$absolute_dst")
Run Code Online (Sandbox Code Playgroud)


小智 8

简短的回答:

cd $source_folder
pax -rwlpe . $dest_folder
Run Code Online (Sandbox Code Playgroud)


Ada*_*tes 6

rsync -av --link-dest="$PWD/dirA" dirA/ dirB

如果您碰巧已经rsync安装了这个命令,那么这是一个快速简单的命令。为了处理符号链接,您可能需要选择--links, --copy-links, --copy-unsafe-links--safe-links

从 rsync 手册页:

--link-dest=DIR         hardlink to files in DIR when unchanged
 -l, --links                 copy symlinks as symlinks
 -L, --copy-links            transform symlink into referent file/dir
--copy-unsafe-links     only "unsafe" symlinks are transformed
--safe-links            ignore symlinks that point outside the tree
Run Code Online (Sandbox Code Playgroud)

编辑:

  • 修复了@MichaelR 评论后的命令。谢谢你!
  • 使用 rsync 2.6.9 在 MacOS 上测试如下
$ cd /tmp && rm -rf a b; mkdir a && touch a/c && echo "xxx" > a/c && rsync -av --link-dest="$PWD/a" a/ b; 
$ ls -lR a b
building file list ... done
created directory b
./

sent 74 bytes  received 26 bytes  200.00 bytes/sec
total size is 4  speedup is 0.04
a:
total 8
-rw-r--r--  2 user  wheel  4 Aug 26 16:09 c

b:
total 8
-rw-r--r--  2 user  wheel  4 Aug 26 16:09 c
Run Code Online (Sandbox Code Playgroud)