备份时保留所有元数据,但将文件内容转换为零(或空的稀疏文件)

备份时保留所有元数据,但将文件内容转换为零(或空的稀疏文件)

我想备份一个目录,所有内容与原始文件相同,只是文件内容转换为全零(稀疏文件),并且保持相同的文件大小。例如,我有

  • 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等)。findcptarddtruncate

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/{}额外功能。如果您的权限受限于此,请改用以下代码片段:findfind

# 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 {} +

相关内容