假设我有一个gzip压缩的tar-ball compressionArchive.tgz(+100个文件,总计+ 5gb)。
删除与给定文件名模式匹配的所有条目(例如prefix * .jpg),然后将其再次存储在gzip:ed tar球中的最快方法是什么?
替换旧存档或创建新存档并不重要,以最快的速度为准。
假设我有一个gzip压缩的tar-ball compressionArchive.tgz(+100个文件,总计+ 5gb)。
删除与给定文件名模式匹配的所有条目(例如prefix * .jpg),然后将其再次存储在gzip:ed tar球中的最快方法是什么?
替换旧存档或创建新存档并不重要,以最快的速度为准。
Answers:
使用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
可能会覆盖第一个尚未读取的文件区域)。
不要低估简单的方法:它可能足够快达到您的目的。使用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()
tar
,您可能要添加p
选项。
为此,您可能必须将.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 .
我喜欢@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$'
。