【问题标题】:Concatenate tar files so that the resulting tar can be opened without the -i option连接 tar 文件,以便可以在没有 -i 选项的情况下打开生成的 tar
【发布时间】:2021-07-10 05:02:55
【问题描述】:

我得到了包含很多非常小的 JSON 文件的 tar 档案。每天我都会得到一个新的 tar 存档。现在我想把每天的 tar 档案合并成一个每年的 tar 档案并压缩它。我使用以下 bash 脚本来做到这一点:

tar -cf "/mnt/archive/archive - 2020.tar" --files-from /dev/null
for f in /mnt/data/logs/2020/logs-main-2020-??-??.tar
do
    tar -n --concatenate --file="/mnt/archive/archive - 2020.tar" $f
done

pxz -T6 -c "/mnt/archive/archive - 2020.tar" > "/mnt/archive/archive - 2020.tar.xz"
rm "/mnt/archive/archive - 2020.tar"

这可行,但是主 tar 越大,tar 文件的连接就越慢。

我可以使用 cat 指令将所有 tar 简单地添加在一起,但生成的存档随后包含原始 tar 的所有存档结束空标记。因此,生成的 tar 必须使用 -i 选项打开,这不是使用生成的 tar 的系统的选项。

如何在不需要慢速 tar 连接的情况下连接 tar 文件,并且仍然可以创建有效的 tar 而中间没有空值?我可以做一些 cat、un-tar、re-tar、compress pipe 吗?

  • 我在输入 tars 的 JSON 文件名中没有任何空格字符,例如换行符
  • 我在 CentOS 7 上使用 GNU tar v1.26
  • 每个输入 tar 大约 1GB,因此无法将它们保存在内存中
  • 无需检查输出 tar 是否有重复条目。输入 tar 的创建方式确保它们没有重复的 JSON 文件

【问题讨论】:

  • 也许看看其他存档格式,如 7​​z 或 zip(浏览手册页,有一个看起来很有希望的 copy 操作)?还是将所有日常档案解压到一​​棵树中,然后一次性全部解压?
  • (我也会考虑使用 zstandard 而不是 xz 进行压缩;压缩比几乎一样快,但速度明显更快)。

标签: linux bash tar


【解决方案1】:

几个基于 perl 的方法:

首先,一个脚本使用核心Archive::Tar模块读取现有的tar文件并创建一个新的(由于模块的限制,它必须将合并后的目标tar文件的数据一次性保存在内存中写它;可能是大量数据的问题):

#!/usr/bin/env perl
use warnings;
use strict;
use feature qw/say/;
use Archive::Tar;

# First argument is the new tar file to create, rest are ones to
# copy files from.

die "Usage: $0 DESTFILE SOURCEFILE ...\n" unless @ARGV >= 2;

my $destfile = shift;
my $dest = Archive::Tar->new;

foreach my $file (@ARGV) {
  my $src = Archive::Tar->iter($file) or exit 1;
  say "Adding contents of $file";
  while (my $file = $src->() ) {
    my $name = $file->full_path;
    say "\t$name";
    $dest->add_data($name, $file->get_content,
                    { mtime => $file->mtime,
                      size => $file->size,
                      mode => $file->mode,
                      uid => $file->uid,
                      gid => $file->gid,
                      type => $file->type,
                      devmajor => $file->devmajor,
                      devminor => $file->devminor,
                      linkname => $file->linkname
                    })
      or exit 1;
  }
}

$dest->write($destfile) or exit 1;
say "Wrote $destfile";

用法:

perl tarcat.pl "/mnt/archive/archive - 2020.tar" /mnt/data/logs/2020/logs-main-2020-??-??.tar

或使用Archive::Tar::Merge 的单线器(如果提供,请通过您的操作系统包管理器或最喜欢的 CPAN 客户端安装;不确定其内存限制):

perl -MArchive::Tar::Merge -e '
    Archive::Tar::Merge->new(dest_tarball => $ARGV[0],
                             source_tarballs => [ @ARGV[1..$#ARGV] ])->merge
' "/mnt/archive/archive - 2020.tar" /mnt/data/logs/2020/logs-main-2020-??-??.tar

【讨论】:

  • 感谢您的建议,但由于合并大小,无法在内存中执行此操作。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-09-01
  • 2015-08-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多