就地提取 tar 存档

ano*_*ard 16 linux extract tar archiving

我在这里有点进退两难...

我需要将大约 70 GB 的文件从我的一台服务器移动到另一台,因此我决定将它们打包并发送存档是最快的方法。

但是,接收服务器在收到 tar 存档后只剩下 5 GB 的空间。

有什么方法可以“就地”提取焦油?提取后我不需要保留存档,所以我想知道是否可以这样做。

编辑:应该注意的是,存档已经发送,我想避免通过不同的方法重新发送。

aki*_*ira 11

% tar czf - stuff_to_backup | ssh backupmachine tar xvzf -
Run Code Online (Sandbox Code Playgroud)

这转化为:

  • tar 并将“stuff_to_backup”压缩到标准输出
  • 通过 ssh 登录到“backupmachine”
  • 在 'backupmachine' 上运行 'tar' 并解压来自 stdin 的东西

我个人会使用“rsync over ssh”来传输内容,因为如果连接中断,您可以继续传输内容:

% rsync -ar --progress -e 'ssh' 'stuff_to_backup' user@backupmachine:/backup/
Run Code Online (Sandbox Code Playgroud)

这会将所有内容从“stuff_to_backup”传输到“backupmachine”上的“backup”文件夹。如果连接中断,只需重复该命令。如果 'stuff_to_backup' 中的某些文件发生更改,则重复这些内容,只会传输差异。


Yup*_*ing 6

如果另一台机器有 ssh,我建议你使用 rsync 作为另一种不使用 tar 文件的替代方法:

rsync -avPz /some/dir/ user@machine:/some/other/dir/
Run Code Online (Sandbox Code Playgroud)

并小心领先 /

编辑更新

好吧,如果您无法删除它并重新开始使用 rsync,那么我现在看到这是一个很好的泡菜。我可能会尝试选择性提取并从焦油中删除。

选择性提取:

$ tar xvf googlecl-0.9.7.tar googlecl-0.9.7/README.txt
googlecl-0.9.7/README.txt
Run Code Online (Sandbox Code Playgroud)

选择性删除:

$ tar --delete --file=googlecl-0.9.7.tar googlecl-0.9.7/README.txt
Run Code Online (Sandbox Code Playgroud)

但是,您似乎会为此花费大量时间编写脚本...

  • @Charlie Somerville:您可能必须从存储在 tar 末尾的文件开始,否则您可能会以 tar 创建新存档结束……因此,首先从 tar 末尾删除文件。 (2认同)

Suz*_*Soy 5

基本上,您需要的是将文件通过管道传输到 tar 中的可能性,并在您进行时“砍掉”前端。

在 StackOverflow 上,有人问如何在 front 截断文件,但似乎不可能。您仍然可以以特殊方式用零填充文件的开头,使文件成为稀疏文件,但我不知道如何做到这一点。不过,我们可以截断文件的末尾。但是 tar 需要向前读取存档,而不是向后读取。

解决方案1

一个间接级别可以解决所有问题。首先就地反转文件,然后向后读取它(这将导致向前读取原始文件)并在执行时截断反转文件的末尾。

您需要编写一个程序(c、python 等)来逐块交换文件的开头和结尾,然后将这些块通过管道传输到 tar,同时一次截断一个文件。这是解决方案 2 的基础,它可能更易于实现。

解决方案2

另一种方法是将文件就地拆分成小块,然后在我们提取它们时删除这些块。以下代码的块大小为 1 兆字节,请根据您的需要进行调整。更大更快,但在拆分和提取期间会占用更多的中间空间。

拆分文件 archive.tar :

archive="archive.tar"
chunkprefix="chunk_"
# 1-Mb chunks :
chunksize=1048576

totalsize=$(wc -c "$archive" | cut -d ' ' -f 1)
currentchunk=$(((totalsize-1)/chunksize))
while [ $currentchunk -ge 0 ]; do
    # Print current chunk number, so we know it is still running.
    echo -n "$currentchunk "
    offset=$((currentchunk*chunksize))
    # Copy end of $archive to new file
    tail -c +$((offset+1)) "$archive" > "$chunkprefix$currentchunk"
    # Chop end of $archive
    truncate -s $offset "$archive"
    currentchunk=$((currentchunk-1))
done
Run Code Online (Sandbox Code Playgroud)

将这些文件通过管道传输到 tar(注意我们需要在第二个终端中使用 chunkprefix 变量):

mkfifo fifo
# In one terminal :
(while true; do cat fifo; done) | tar -xf -
# In another terminal :
chunkprefix="chunk_"
currentchunk=0
while [ -e "$chunkprefix$currentchunk" ]; do
    cat "$chunkprefix$currentchunk" && rm -f "$chunkprefix$currentchunk"
    currentchunk=$((currentchunk+1))
done > fifo
# When second terminal has finished :
# flush caches to disk :
sync
# wait 5 minutes so we're sure tar has consumed everything from the fifo.
sleep 300
rm fifo
# And kill (ctrl-C) the tar command in the other terminal.
Run Code Online (Sandbox Code Playgroud)

由于我们使用命名管道 ( mkfifo fifo),因此您不必一次对所有块进行管道传输。如果您的空间非常紧张,这会很有用。您可以按照以下步骤操作:

  • 将最后的 10Gb 块移动到另一个磁盘,
  • 用你仍然拥有的块开始提取,
  • while [ -e … ]; do cat "$chunk…; done循环完成时(第二个终端):
  • 不要停止tar命令,不要删除fifo(第一个终端),但您可以运行sync,以防万一,
  • 将一些您知道已完成的提取文件(tar 不会停止等待数据完成提取这些文件)移动到另一个磁盘,
  • 将剩余的块移回,
  • 通过while [ -e … ]; do cat "$chunk…; done再次运行这些行来恢复提取。

当然,这都是高级电压,您首先要检查虚拟存档上的一切是否正常,因为如果您犯了错误,那么再见数据

你永远不会知道第一个终端 ( tar) 是否真的完成了对 fifo 的内容的处理,所以如果你愿意,你可以运行它,但你不可能与另一个磁盘无缝交换块:

chunkprefix="chunk_"
currentchunk=0
while [ -e "$chunkprefix$currentchunk" ]; do
    cat "$chunkprefix$currentchunk" && rm -f "$chunkprefix$currentchunk"
    currentchunk=$((currentchunk+1))
done | tar -xf -
Run Code Online (Sandbox Code Playgroud)

免责声明

请注意,要使所有这些工作,您的 shell、tail 和 truncate 必须正确处理 64 位整数(您不需要 64 位计算机或操作系统)。我的是这样,但是如果您在没有这些要求的系统上运行上述脚本,您将丢失 archive.tar 中的所有数据

并且在任何情况下,除此之外的其他问题都会丢失archive.tar 中的所有数据,因此请确保对数据进行备份。