就地提取tar存档


14

我在这里有点困境...

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

但是,接收服务器在接收tar归档文件后仅剩余5 GB的空间。

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

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

Answers:


11
% tar czf - stuff_to_backup | ssh backupmachine tar xvzf -

转换为:

  • tar并将'stuff_to_backup'压缩为stdout
  • 通过ssh登录到“ backupmachine”
  • 在“ backupmachine”上运行“ tar”,然后解压缩来自stdin的内容

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

% rsync -ar --progress -e 'ssh' 'stuff_to_backup' user@backupmachine:/backup/

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


看到我编辑过的问题
匿名

@Charlie Somerville:是的,您首先忽略了重要部分。:)
akira 2010年

6

如果另一台计算机上有ssh,我建议您将rsync作为不使用tar文件的另一种选择:

rsync -avPz /some/dir/ user@machine:/some/other/dir/

并注意领导 /

编辑更新

好吧,如果您无法删除它并使用rsync重新启动,我知道这现在是一个很棒的泡菜。我可能会尝试选择性地提取并从tar中删除。

选择性提取物:

$ tar xvf googlecl-0.9.7.tar googlecl-0.9.7/README.txt
googlecl-0.9.7/README.txt

选择性删除:

$ tar --delete --file=googlecl-0.9.7.tar googlecl-0.9.7/README.txt

但是,看来您将花费大量时间为此编写脚本...


看到我编辑过的问题
匿名

见我编辑过的答案...祝你好运:-/
YuppieNetworking 2010年

感谢您的修改。这些文件实际上是用数字命名的,因此在bash中进行快速for循环可能就可以解决问题。
匿名co

1
@Charlie Somerville:您可能必须先从存储在tar末尾的文件开始,否则可能会以tar创建一个新的存档结尾...因此,请首先从tar末尾删除文件。
akira 2010年

5

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

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

解决方案1

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

您需要编写一个程序(c,python等)以逐块地交换文件的开头和结尾,然后将这些块通过管道传送到tar,同时一次截断文件。这是解决方案2的基础,解决方案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

将这些文件通过管道传输到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.

由于我们使用命名管道(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 -

免责声明

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

并且在任何其他情况下,如果出现错误,则无论如何都会丢失archive.tar中的所有数据,因此请确保已备份了数据。


0

如果有要移动的目标文件,请尝试剥离它们。这样可以节省大量空间。

$ strip `find . -name "*.bin"`
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.