有效地从大型 .tgz 中删除文件

有效地从大型 .tgz 中删除文件

假设我有一个 gzip 压缩的 tar-ballcompressedArchive.tgz(+100 个文件,总共+5gb)。

删除与给定文件名模式匹配的所有条目(例如前缀*.jpg)的最快方法是什么,然后再次将剩余部分存储在 gzip:ed tar-ball 中?

替换旧档案或创建新档案并不重要,无论哪个最快。

答案1

使用 GNU tar,您可以执行以下操作:

pigz -d < file.tgz |
  tar --delete --wildcards -f - '*/prefix*.jpg' |
  pigz > newfile.tgz

bsdtar

pigz -d < file.tgz |
  bsdtar -cf - --exclude='*/prefix*.jpg' @- |
  pigz > newfile.tgz

pigz是多线程版本gzip)。

您可以覆盖文件本身,如下所示:

{ pigz -d < file.tgz |
    tar --delete --wildcards -f - '*/prefix*.jpg' |
    pigz &&
    perl -e 'truncate STDOUT, tell STDOUT'
} 1<> file.tgz

但这是相当危险的,特别是如果结果最终压缩程度低于原始文件(在这种情况下,第二个文件pigz可能最终会覆盖第一个文件尚未读取的文件区域)。

答案2

不要低估简单的方法:它可能足够快以满足您的目的。和AVFS以目录形式访问存档:

cd ~/.avfs/path/to/original.tar.gz\#
pax -w -s '/^.*\.jpg$//' | gzip >/path/to/filtered.tar.gz        # POSIX
tar -czf /path/to/filtered.tar.gz -s '/^.*\.jpg$//' .            # BSD
tar -czf /path/to/filtered.tar.gz --transform '/^.*\.jpg$//' .   # GNU

使用更原始的工具,首先提取排除文件的文件.jpg,然后创建新的存档。

mkdir tmpdir && cd tmpdir
<original.tar.gz gzip -d | pax -r -pe -s '/^.*\.jpg$//'
pax -w . | gzip >filtered.tar.gz
cd .. && rm -rf tmpdir

如果你的焦油有--exclude

mkdir tmpdir && cd tmpdir
tar -xzf original.tar.gz --exclude='*.jpg'
tar -czf filtered.tar.gz .
cd .. && rm -rf tmpdir

然而,如果您不以 root 身份运行它,这可能会破坏文件所有权和模式。为了获得最佳结果,请使用快速文件系统上的临时目录 - tmpfs(如果您有足够大的文件系统)。

对归档器充当传递(即读取归档文件和写入归档文件)的支持往往是有限的。GNU tar 可以从档案中删除成员--delete操作选项(“据报告,该选项在充当从到 的过滤器--delete时可以正常工作。”),这可能是您的最佳选择。tarstdinstdout

您可以用几行 Python 代码创建强大的存档过滤器。它是tarfile库可以从不可查找的流中读取和写入,并且您可以在Python中使用任意代码来过滤、重命名、修改......

#!/usr/bin/python
import re, sys, tarfile
source = tarfile.open(fileobj=sys.stdin, mode='r|*')
dest = tarfile.open(fileobj=sys.stdout, mode='w|gz')
for member in source:
    if not (member.isreg() and re.match(r'.*\.jpg\Z', member.name)):
        sys.stderr.write(member.name + '\n')
        dest.addfile(member, source.extractfile(member))
dest.close()

答案3

使用 Mac OSX 上的 tar,您可以执行以下操作:

tar -czf b.tgz --exclude '*.jpg' @a.tgz
mv b.tgz a.tgz

答案4

我用:

tar -xvf myLarge.gz --exclude "prefix" | tar -czvf myLarge.gz -T -

这会:

  1. 提取除包含“的文件”之外的所有文件字首
  2. ( -T -) 将其余内容通过管道传输至 tar 并重新压缩 myLarge.gz

相关内容