我想备份一个目录,所有内容与原始文件相同,只是文件内容转换为全零(稀疏文件),并且保持相同的文件大小。例如,我有
- dir/file1 包含 1 GB 非零数据
- dir/file2 包含 2 GB 非零数据
- ...(该目录足够大,包含更多文件和子目录)
我需要
- dir_bak/file1 具有与 dir/file1.txt 完全相同的元数据和 1 GB 的零(或相应的稀疏文件)
- dir_bak/file2 具有与 dir/file2.txt 完全相同的元数据和 2 GB 的零(或相应的稀疏文件)
- ...
结果文件以及子目录结构应该被压缩为档案(首选)或稀疏存储,这样只会使用很少的磁盘空间。
这里的一个关键问题是我没有更多磁盘空间来进行完整备份,所以请不要想出先进行完整备份然后再处理的解决方案。在整个过程中,请不要占用太多额外的磁盘空间。
仅供参考,它在ext4 、linux 上支持基本的 shell 命令(如、、、、、、ls
等)。find
cp
tar
dd
truncate
PS 除了 shell 脚本外,任何其他类型的备份/快照/映像/存档解决方案,只要满足需求(具有完整元数据的空内容),也都是受欢迎的。
答案1
首先,使用您知道的命令复制元数据和结构(sudo
如果需要请使用):
cp -R --attributes-only --preserve=all dir dir_bak
现在 中的常规文件dir_bak
大小均为 0。我们将修复此问题。对于 中的每个常规文件,dir_bak
我们将读取 中的相应文件的大小dir
,并相应地truncate
读取 中的文件的大小dir_bak
。如果文件系统支持稀疏文件,则 中的文件dir_bak
将完全稀疏。然后我们需要touch
修复受影响的 mtime truncate
(ctime 也受影响,但你不能轻易改变它;请注意我们的代码cp …
首先不保存 ctime)。问问自己是否需要sudo
所有这些。
重要的:
cd dir_bak
如果您在,请仔细检查dir_bak
。在另一个目录中调用以下find …
命令(或sudo find …
如果需要)可能会影响目录中的文件,您可能会丢失数据。
还要注意,你需要path/to/source/dir/
用实际的源路径dir/
(带尾部斜杠)替换。如果你使用了cp …
我提供的确切命令,路径可能是../dir/
;否则应该是其他路径。无论如何,你应该调整代码。无论如何满的到源的实际路径dir/
是一个很好的替代方案。
# make sure you're in dir_bak
# MAKE SURE you're in dir_bak
find . -type f -print \
-exec truncate -r 'path/to/source/dir/'{} {} \; \
-exec touch -r 'path/to/source/dir/'{} {} \;
以上内容适用于 GNU find
。一般来说,find
必须将{}
provided 的一个出现替换为单独的参数。支持替换多个{}
和/或仅替换{}
为参数的子字符串(如)是您可能缺少的…/dir/{}
额外功能。如果您的权限受限于此,请改用以下代码片段:find
find
# make sure you're in dir_bak
# MAKE SURE you're in dir_bak
find . -type f -exec sh -c '
for f do
printf "%s\n" "$f"
r="path/to/source/dir/$f"
truncate -r "$r" "$f"
touch -r "$r" "$f"
done
' find-sh {} +
-print
或者printf
不是真正需要,它只是为了显示进度。
我不确定是否所有的实现都truncate
支持-r
。如果你truncate
不支持,那么请使用此代码片段(它仍然使用touch -r
):
# make sure you're in dir_bak
# MAKE SURE you're in dir_bak
find . -type f -exec sh -c '
for f do
printf "%s\n" "$f"
r="path/to/source/dir/$f"
s=$(<"$r" wc -c)
[ "$?" -eq 0 ] || continue
truncate -s "$s" "$f"
touch -r "$r" "$f"
done
' find-sh {} +