将整个目录(例如 )镜像original/
到新目录(例如 )的最佳方法是什么mirror/
,该目录具有结构mirror/data/
和mirror/tree/
,这样
- 目录
original/
或其任何子目录中的每个文件都硬链接到文件在mirror/data
- 其文件名是其内容的唯一标识符,例如其内容的哈希值,以及
- 它是从一个点开始符号链接的,
mirror/tree
该点的相对路径对应于 中原始文件的相对路径original
,
以便可以轻松恢复?
这个功能可能是由现有的某种工具实现的吗? – 允许灵活选择命令来根据文件内容创建唯一标识符的命令。
例如,假设只有一个文件original/something
,它是一个包含单词“data”的文本文件。然后我想在 上运行脚本或命令original
,结果是:
$ tree original mirror
original
└── something
mirror
├── data
│ └── 6667b2d1aab6a00caa5aee5af8…
└── tree
└── original
└── something -> ../../data/6667b2d1aab6a00caa5aee5af8…
5 directories, 3 files
在这里,该文件667b…
是一个硬链接original/something
,其文件名是该文件的 sha256sum 哈希值。请注意,为了便于阅读,我已缩写了文件名。
我希望能够通过它的镜子完美地还原原来的样子。
我知道我可以编写一个脚本来做到这一点,但在我这样做之前,可能会犯错误并丢失一些数据,我想知道是否有任何工具已经安全地实现了这一点(我没有找到任何工具)远)或者是否有任何陷阱。
背景:我想保留跟踪重命名的目录的存档,但我不需要版本控制。我知道git-annex
使用 git 存储库会产生大量开销,但我只需要使用目录结构的符号链接将目录的内容镜像到文件名是其内容的哈希值的文件。然后我可以使用 git-diff 来跟踪重命名。我不完全理解 git-annex 在做什么,所以我不想信任它来归档我的数据。所以我正在寻找一种更轻、干扰更少的替代方案。
答案1
实施起来并不是那么困难。在 GNU 系统上(对于ln -r
和sha1sum -z
)和 with zsh
:
mkdir -p mirror/{data,tree} &&
find original -type f -exec sha1sum -z {} + |
while IFS= read -rd '' rec; do
sum=$rec[1,40] file=$rec[43,-1]
ln -f -- $file mirror/data/$sum &&
mkdir -p -- mirror/tree/${${file#*/}:h} &&
ln -rs mirror/data/$sum mirror/tree/${file#*/}
done
请注意,它不会尝试保留目录的元数据(所有权、权限、mtime/atime、ACL、扩展属性)。如果多个文件具有相同的内容,则最终链接的文件mirror/data
将或多或少是随机的,因为它将取决于find
报告它们的顺序,而这是不确定的。
另请注意,空目录和既不是目录也不是常规文件(例如符号链接、fifo、设备...)的文件不会被复制。
可以使用 GNU 来复制包含特殊文件和尽可能多的元数据的目录结构tar
:
set -o pipefail
mkdir -p mirror/{data,tree} &&
(
cd original && find . ! -type f -print0 |
tar -cf - --xattrs --null --verbatim-files-from --no-recursion -T -
) | (
cd mirror/tree && tar -xpf - --xattrs
) &&
find original -type f -exec sha1sum -z {} + |
while IFS= read -rd '' rec; do
sum=$rec[1,40] file=$rec[43,-1]
ln -f -- $file mirror/data/$sum &&
ln -rs mirror/data/$sum mirror/tree/${file#*/}
done
但请注意,在这些目录中创建这些符号链接将更新它们的上次修改时间。