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


14

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

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

替换旧存档或创建新存档并不重要,以最快的速度为准。


Answers:


14

使用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可能会覆盖第一个尚未读取的文件区域)。


谢谢你的回答,赞成。将于下周运行基准测试,以查看哪一个对我的存档和系统的性能更好,然后接受。
Aksel Willgert

8

不要低估简单的方法:它可能足够快达到您的目的。使用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焦油可以从档案中删除成员--delete操作选项(以下简称“ --delete选项已被报道时能正常工作tar从一个过滤器的作用stdin,以stdout。”),这可能是您的最佳选择。

您可以使用几行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()

如果以root身份运行,它将也破坏uid / usernames,除非在具有与uid文件最初创建tar文件时相同的uid <=>用户名映射的计算机上完成。ACL,扩展属性也可能会受到影响。使用tar,您可能要添加p选项。
斯特凡Chazelas

2

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

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

1

为此,您可能必须将.tgz文件的所有内容提取到本地目录中,然后擦除不需要的文件,然后重新压缩.tgz。

它很长,您需要足够的可用磁盘空间,但是据我所知,没有其他方法可以做到这一点。

假设您已经有一些路径/tmpdir/withalotofspace,这些路径具有足够的可用空间(使用来检查 df -h /tmpdir/withalotofspace),则可以执行以下操作:

$ cd /tmpdir/withalotofspace
$ tar -xvfz /path/to/compressedArchive.tgz
$ find /tmpdir/withalotofspace/ -type f -iname '*.jpg' -delete
$ tar -cvzf /path/to/purgedcompressedArchive.tgz .

正如其他答案所示,通过管道传输,无需在磁盘上随时存储未压缩的数据
Tobias Kienzler 2013年

0

我喜欢@Gilles的回答,但可以进一步简化它。解压缩后,例如gunzip foo.tgz,文件将为foo.tar,可以使用删除文件tar -f foo.tar --delete file|directory。以下是从tar文件中删除目录的示例。

    phablet@ubuntu-phablet:~/Downloads$ tar -cvf moo.tar moo1/
    moo1/
    moo1/moo2/
    moo1/moo2/moo3/
    moo1/moo2/moo3/moo4/
    moo1/moo2/moo3/moo4/moo5/
    phablet@ubuntu-phablet:~/Downloads$ tar -tf moo.tar 
    moo1/
    moo1/moo2/
    moo1/moo2/moo3/
    moo1/moo2/moo3/moo4/
    moo1/moo2/moo3/moo4/moo5/
    phablet@ubuntu-phablet:~/Downloads$ tar -f moo.tar --delete "moo1/moo2/moo3"
    phablet@ubuntu-phablet:~/Downloads$ tar -tf moo.tar 
    moo1/
    moo1/moo2/

可以找到特定的文件类型tar -tf foo.tar|egrep -i '.jpg$'

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.